Changeset - r27884:803962be0328
[Not reviewed]
master
! ! !
Tyler Trahan - 13 months ago 2023-08-16 13:43:31
tyler@tylertrahan.com
Codechange: Move date consts and functions to CalendarTime and TimerGameCalendar classes
57 files changed:
Changeset was too big and was cut off... Show full diff anyway
0 comments (0 inline, 0 general)
src/aircraft_cmd.cpp
Show inline comments
 
@@ -432,49 +432,49 @@ static void CheckIfAircraftNeedsService(
 
	}
 
}
 

	
 
Money Aircraft::GetRunningCost() const
 
{
 
	const Engine *e = this->GetEngine();
 
	uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost);
 
	return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
 
}
 

	
 
void Aircraft::OnNewDay()
 
{
 
	if (!this->IsNormalAircraft()) return;
 

	
 
	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
 

	
 
	CheckOrders(this);
 

	
 
	CheckVehicleBreakdown(this);
 
	AgeVehicle(this);
 
	CheckIfAircraftNeedsService(this);
 

	
 
	if (this->running_ticks == 0) return;
 

	
 
	CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * Ticks::DAY_TICKS));
 
	CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
 

	
 
	this->profit_this_year -= cost.GetCost();
 
	this->running_ticks = 0;
 

	
 
	SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
	SetWindowClassesDirty(WC_AIRCRAFT_LIST);
 
}
 

	
 
static void HelicopterTickHandler(Aircraft *v)
 
{
 
	Aircraft *u = v->Next()->Next();
 

	
 
	if (u->vehstatus & VS_HIDDEN) return;
 

	
 
	/* if true, helicopter rotors do not rotate. This should only be the case if a helicopter is
 
	 * loading/unloading at a terminal or stopped */
 
	if (v->current_order.IsType(OT_LOADING) || (v->vehstatus & VS_STOPPED)) {
 
		if (u->cur_speed != 0) {
 
			u->cur_speed++;
 
			if (u->cur_speed >= 0x80 && u->state == HRS_ROTOR_MOVING_3) {
 
				u->cur_speed = 0;
 
			}
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -946,49 +946,49 @@ int DrawVehiclePurchaseInfo(int left, in
 

	
 
		case VEH_AIRCRAFT:
 
			y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
 
			break;
 
	}
 

	
 
	if (articulated_cargo) {
 
		/* Cargo type + capacity, or N/A */
 
		int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);
 

	
 
		if (new_y == y) {
 
			SetDParam(0, CT_INVALID);
 
			SetDParam(2, STR_EMPTY);
 
			DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
 
			y += FONT_HEIGHT_NORMAL;
 
		} else {
 
			y = new_y;
 
		}
 
	}
 

	
 
	/* Draw details that apply to all types except rail wagons. */
 
	if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
 
		/* Design date - Life length */
 
		SetDParam(0, ymd.year);
 
		SetDParam(1, DateToYear(e->GetLifeLengthInDays()));
 
		SetDParam(1, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays()));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		/* Reliability */
 
		SetDParam(0, ToPercent16(e->reliability));
 
		DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
 

	
 
	/* Additional text from NewGRF */
 
	y = ShowAdditionalText(left, right, y, engine_number);
 

	
 
	/* The NewGRF's name which the vehicle comes from */
 
	const GRFConfig *config = GetGRFConfig(e->GetGRFID());
 
	if (_settings_client.gui.show_newgrf_name && config != nullptr)
 
	{
 
		DrawString(left, right, y, config->GetName(), TC_BLACK);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	return y;
 
}
src/cheat_gui.cpp
Show inline comments
 
@@ -83,49 +83,49 @@ static int32_t ClickChangeCompanyCheat(i
 
/**
 
 * Allow (or disallow) changing production of all industries.
 
 * @param new_value new value
 
 * @param change_direction unused
 
 * @return New value allowing change of industry production.
 
 */
 
static int32_t ClickSetProdCheat(int32_t new_value, int32_t change_direction)
 
{
 
	_cheats.setup_prod.value = (new_value != 0);
 
	InvalidateWindowClassesData(WC_INDUSTRY_VIEW);
 
	return _cheats.setup_prod.value;
 
}
 

	
 
extern void EnginesMonthlyLoop();
 

	
 
/**
 
 * Handle changing of the current year.
 
 * @param new_value The chosen year to change to.
 
 * @param change_direction +1 (increase) or -1 (decrease).
 
 * @return New year.
 
 */
 
static int32_t ClickChangeDateCheat(int32_t new_value, int32_t change_direction)
 
{
 
	/* Don't allow changing to an invalid year, or the current year. */
 
	auto new_year = Clamp(TimerGameCalendar::Year(new_value), MIN_YEAR, MAX_YEAR);
 
	auto new_year = Clamp(TimerGameCalendar::Year(new_value), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
	if (new_year == TimerGameCalendar::year) return static_cast<int32_t>(TimerGameCalendar::year);
 

	
 
	TimerGameCalendar::YearMonthDay ymd;
 
	TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
 
	TimerGameCalendar::Date new_date = TimerGameCalendar::ConvertYMDToDate(new_year, ymd.month, ymd.day);
 

	
 
	/* Shift cached dates before we change the date. */
 
	for (auto v : Vehicle::Iterate()) v->ShiftDates(new_date - TimerGameCalendar::date);
 
	LinkGraphSchedule::instance.ShiftDates(new_date - TimerGameCalendar::date);
 

	
 
	/* Now it's safe to actually change the date. */
 
	TimerGameCalendar::SetDate(new_date, TimerGameCalendar::date_fract);
 

	
 
	EnginesMonthlyLoop();
 
	SetWindowDirty(WC_STATUS_BAR, 0);
 
	InvalidateWindowClassesData(WC_BUILD_STATION, 0);
 
	InvalidateWindowClassesData(WC_BUS_STATION, 0);
 
	InvalidateWindowClassesData(WC_TRUCK_STATION, 0);
 
	InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
 
	ResetSignalVariant();
 
	return static_cast<int32_t>(TimerGameCalendar::year);
 
}
 

	
 
/**
 
@@ -299,49 +299,49 @@ struct CheatWindow : Window {
 

	
 
			y += this->line_height;
 
		}
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		if (widget != WID_C_PANEL) return;
 

	
 
		uint width = 0;
 
		for (int i = 0; i != lengthof(_cheats_ui); i++) {
 
			const CheatEntry *ce = &_cheats_ui[i];
 
			switch (ce->type) {
 
				case SLE_BOOL:
 
					SetDParam(0, STR_CONFIG_SETTING_ON);
 
					width = std::max(width, GetStringBoundingBox(ce->str).width);
 
					SetDParam(0, STR_CONFIG_SETTING_OFF);
 
					width = std::max(width, GetStringBoundingBox(ce->str).width);
 
					break;
 

	
 
				default:
 
					switch (ce->str) {
 
						/* Display date for change date cheat */
 
						case STR_CHEAT_CHANGE_DATE:
 
							SetDParam(0, TimerGameCalendar::ConvertYMDToDate(MAX_YEAR, 11, 31));
 
							SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR, 11, 31));
 
							width = std::max(width, GetStringBoundingBox(ce->str).width);
 
							break;
 

	
 
						/* Draw coloured flag for change company cheat */
 
						case STR_CHEAT_CHANGE_COMPANY:
 
							SetDParamMaxValue(0, MAX_COMPANIES);
 
							width = std::max(width, GetStringBoundingBox(ce->str).width + WidgetDimensions::scaled.hsep_wide * 4);
 
							break;
 

	
 
						default:
 
							SetDParam(0, INT64_MAX);
 
							width = std::max(width, GetStringBoundingBox(ce->str).width);
 
							break;
 
					}
 
					break;
 
			}
 
		}
 

	
 
		this->line_height = std::max(this->box.height, this->icon.height);
 
		this->line_height = std::max<uint>(this->line_height, SETTING_BUTTON_HEIGHT);
 
		this->line_height = std::max<uint>(this->line_height, FONT_HEIGHT_NORMAL) + WidgetDimensions::scaled.framerect.Vertical();
 

	
 
		size->width = width + WidgetDimensions::scaled.hsep_wide * 4 + this->box.width + SETTING_BUTTON_WIDTH /* stuff on the left */ + WidgetDimensions::scaled.hsep_wide * 2 /* extra spacing on right */;
 
		size->height = WidgetDimensions::scaled.framerect.Vertical() + this->line_height * lengthof(_cheats_ui);
src/company_gui.cpp
Show inline comments
 
@@ -1840,59 +1840,59 @@ struct CompanyInfrastructureWindow : Win
 

	
 
	uint total_width; ///< String width of the total cost line.
 

	
 
	CompanyInfrastructureWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
 
	{
 
		this->UpdateRailRoadTypes();
 

	
 
		this->InitNested(window_number);
 
		this->owner = (Owner)this->window_number;
 
	}
 

	
 
	void UpdateRailRoadTypes()
 
	{
 
		this->railtypes = RAILTYPES_NONE;
 
		this->roadtypes = ROADTYPES_NONE;
 

	
 
		/* Find the used railtypes. */
 
		for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
 
			if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
 

	
 
			this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
 
		}
 

	
 
		/* Get the date introduced railtypes as well. */
 
		this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DATE);
 
		this->railtypes = AddDateIntroducedRailTypes(this->railtypes, CalendarTime::MAX_DATE);
 

	
 
		/* Find the used roadtypes. */
 
		for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
 
			if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
 

	
 
			this->roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes;
 
		}
 

	
 
		/* Get the date introduced roadtypes as well. */
 
		this->roadtypes = AddDateIntroducedRoadTypes(this->roadtypes, MAX_DATE);
 
		this->roadtypes = AddDateIntroducedRoadTypes(this->roadtypes, CalendarTime::MAX_DATE);
 
		this->roadtypes &= ~_roadtypes_hidden_mask;
 
	}
 

	
 
	/** Get total infrastructure maintenance cost. */
 
	Money GetTotalMaintenanceCost() const
 
	{
 
		const Company *c = Company::Get((CompanyID)this->window_number);
 
		Money total;
 

	
 
		uint32_t rail_total = c->infrastructure.GetRailTotal();
 
		for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
 
			if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
 
		}
 
		total += SignalMaintenanceCost(c->infrastructure.signal);
 

	
 
		uint32_t road_total = c->infrastructure.GetRoadTotal();
 
		uint32_t tram_total = c->infrastructure.GetTramTotal();
 
		for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
 
			if (HasBit(this->roadtypes, rt)) total += RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total);
 
		}
 

	
 
		total += CanalMaintenanceCost(c->infrastructure.water);
 
		total += StationMaintenanceCost(c->infrastructure.station);
 
		total += AirportMaintenanceCost(c->index);
src/date_gui.cpp
Show inline comments
 
@@ -23,50 +23,50 @@
 

	
 

	
 
/** Window to select a date graphically by using dropdowns */
 
struct SetDateWindow : Window {
 
	SetDateCallback *callback; ///< Callback to call when a date has been selected
 
	void *callback_data;       ///< Callback data pointer.
 
	TimerGameCalendar::YearMonthDay date; ///< The currently selected date
 
	TimerGameCalendar::Year min_year; ///< The minimum year in the year dropdown
 
	TimerGameCalendar::Year max_year; ///< The maximum year (inclusive) in the year dropdown
 

	
 
	/**
 
	 * Create the new 'set date' window
 
	 * @param desc the window description
 
	 * @param window_number number of the window
 
	 * @param parent the parent window, i.e. if this closes we should close too
 
	 * @param initial_date the initial date to show
 
	 * @param min_year the minimum year to show in the year dropdown
 
	 * @param max_year the maximum year (inclusive) to show in the year dropdown
 
	 * @param callback the callback to call once a date has been selected
 
	 */
 
	SetDateWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, TimerGameCalendar::Date initial_date, TimerGameCalendar::Year min_year, TimerGameCalendar::Year max_year, SetDateCallback *callback, void *callback_data) :
 
			Window(desc),
 
			callback(callback),
 
			callback_data(callback_data),
 
			min_year(std::max(MIN_YEAR, min_year)),
 
			max_year(std::min(MAX_YEAR, max_year))
 
			min_year(std::max(CalendarTime::MIN_YEAR, min_year)),
 
			max_year(std::min(CalendarTime::MAX_YEAR, max_year))
 
	{
 
		assert(this->min_year <= this->max_year);
 
		this->parent = parent;
 
		this->InitNested(window_number);
 

	
 
		if (initial_date == 0) initial_date = TimerGameCalendar::date;
 
		TimerGameCalendar::ConvertDateToYMD(initial_date, &this->date);
 
		this->date.year = Clamp(this->date.year, min_year, max_year);
 
	}
 

	
 
	Point OnInitialPosition(int16_t sm_width, int16_t sm_height, int window_number) override
 
	{
 
		Point pt = { this->parent->left + this->parent->width / 2 - sm_width / 2, this->parent->top + this->parent->height / 2 - sm_height / 2 };
 
		return pt;
 
	}
 

	
 
	/**
 
	 * Helper function to construct the dropdown.
 
	 * @param widget the dropdown widget to create the dropdown for
 
	 */
 
	void ShowDateDropDown(int widget)
 
	{
 
		int selected;
 
		DropDownList list;
src/date_type.h
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * 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.
 
 * 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.
 
 * 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/>.
 
 */
 

	
 
/** @file date_type.h Types related to the dates in OpenTTD. */
 

	
 
#ifndef DATE_TYPE_H
 
#define DATE_TYPE_H
 

	
 
#include "timer/timer_game_calendar.h"
 

	
 
static const int DAYS_IN_YEAR      = 365; ///< days per year
 
static const int DAYS_IN_LEAP_YEAR = 366; ///< sometimes, you need one day more...
 
static const int MONTHS_IN_YEAR    =  12; ///< months per year
 

	
 
static const int SECONDS_PER_DAY   = 2;   ///< approximate seconds per day, not for precise calculations
 

	
 
/*
 
 * ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR and DAYS_TILL_ORIGINAL_BASE_YEAR are
 
 * primarily used for loading newgrf and savegame data and returning some
 
 * newgrf (callback) functions that were in the original (TTD) inherited
 
 * format, where 'TimerGameCalendar::date == 0' meant that it was 1920-01-01.
 
 */
 

	
 
/** The minimum starting year/base year of the original TTD */
 
static constexpr TimerGameCalendar::Year ORIGINAL_BASE_YEAR = 1920;
 
/** The original ending year */
 
static constexpr TimerGameCalendar::Year ORIGINAL_END_YEAR = 2051;
 
/** The maximum year of the original TTD */
 
static constexpr TimerGameCalendar::Year ORIGINAL_MAX_YEAR = 2090;
 

	
 
/**
 
 * Calculate the date of the first day of a given year.
 
 * @param year the year to get the first day of.
 
 * @return the date.
 
 */
 
static constexpr TimerGameCalendar::Date DateAtStartOfYear(TimerGameCalendar::Year year)
 
{
 
	int32_t year_as_int = static_cast<int32_t>(year);
 
	uint number_of_leap_years = (year == 0) ? 0 : ((year_as_int - 1) / 4 - (year_as_int - 1) / 100 + (year_as_int - 1) / 400 + 1);
 

	
 
	return (DAYS_IN_YEAR * year_as_int) + number_of_leap_years;
 
}
 

	
 
/**
 
 * Calculate the year of a given date.
 
 * @param date The date to consider.
 
 * @return the year.
 
 */
 
static inline TimerGameCalendar::Year DateToYear(TimerGameCalendar::Date date)
 
{
 
	return static_cast<int32_t>(date) / DAYS_IN_LEAP_YEAR;
 
}
 

	
 
/**
 
 * The date of the first day of the original base year.
 
 */
 
static constexpr TimerGameCalendar::Date DAYS_TILL_ORIGINAL_BASE_YEAR = DateAtStartOfYear(ORIGINAL_BASE_YEAR);
 

	
 
/** The absolute minimum & maximum years in OTTD */
 
static constexpr TimerGameCalendar::Year MIN_YEAR = 0;
 

	
 
/** The default starting year */
 
static constexpr TimerGameCalendar::Year DEF_START_YEAR = 1950;
 
/** The default scoring end year */
 
static constexpr TimerGameCalendar::Year DEF_END_YEAR = ORIGINAL_END_YEAR - 1;
 

	
 
/**
 
 * MAX_YEAR, nicely rounded value of the number of years that can
 
 * be encoded in a single 32 bits date, about 2^31 / 366 years.
 
 */
 
static constexpr TimerGameCalendar::Year MAX_YEAR = 5000000;
 

	
 
/** The date of the last day of the max year. */
 
static constexpr TimerGameCalendar::Date MAX_DATE = DateAtStartOfYear(MAX_YEAR + 1) - 1;
 

	
 
static constexpr TimerGameCalendar::Year INVALID_YEAR = -1; ///< Representation of an invalid year
 
static constexpr TimerGameCalendar::Date INVALID_DATE = -1; ///< Representation of an invalid date
 

	
 
#endif /* DATE_TYPE_H */
src/depot_gui.cpp
Show inline comments
 
@@ -339,49 +339,49 @@ struct DepotWindow : Window {
 
			case VEH_SHIP:     DrawShipImage(    v, image, this->sel, EIT_IN_DEPOT); break;
 
			case VEH_AIRCRAFT: DrawAircraftImage(v, image, this->sel, EIT_IN_DEPOT); break;
 
			default: NOT_REACHED();
 
		}
 

	
 
		uint diff_x, diff_y;
 
		if (v->IsGroundVehicle()) {
 
			/* Arrange unitnumber and flag horizontally */
 
			diff_x = this->flag_size.width + WidgetDimensions::scaled.hsep_normal;
 
			diff_y = WidgetDimensions::scaled.matrix.top;
 
		} else {
 
			/* Arrange unitnumber and flag vertically */
 
			diff_x = 0;
 
			diff_y = WidgetDimensions::scaled.matrix.top + FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
 
		}
 

	
 
		text = text.WithWidth(this->header_width - WidgetDimensions::scaled.hsep_normal, rtl).WithHeight(FONT_HEIGHT_NORMAL).Indent(diff_x, rtl);
 
		if (free_wagon) {
 
			DrawString(text, STR_DEPOT_NO_ENGINE);
 
		} else {
 
			Rect flag = r.WithWidth(this->flag_size.width, rtl).WithHeight(this->flag_size.height).Translate(0, diff_y);
 
			DrawSpriteIgnorePadding((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, flag, false, SA_CENTER);
 

	
 
			SetDParam(0, v->unitnumber);
 
			DrawString(text, STR_JUST_COMMA, (v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? TC_BLACK : TC_RED);
 
			DrawString(text, STR_JUST_COMMA, (v->max_age - CalendarTime::DAYS_IN_LEAP_YEAR) >= v->age ? TC_BLACK : TC_RED);
 
		}
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		if (widget != WID_D_MATRIX) return;
 

	
 
		bool rtl = _current_text_dir == TD_RTL;
 

	
 
		/* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
 
		const NWidgetCore *wid = this->GetWidget<NWidgetCore>(WID_D_MATRIX);
 

	
 
		/* Set up rect for each cell */
 
		Rect ir = r.WithHeight(this->resize.step_height);
 
		if (this->num_columns != 1) ir = ir.WithWidth(this->resize.step_width, rtl);
 
		ir = ir.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
 

	
 
		/* Draw vertical separators at whole tiles.
 
		 * This only works in two cases:
 
		 *  - All vehicles use VEHICLEINFO_FULL_VEHICLE_WIDTH as reference width.
 
		 *  - All vehicles are 8/8. This cannot be checked for NewGRF, so instead we check for "all vehicles are original vehicles".
 
		 */
 
		if (this->type == VEH_TRAIN && _consistent_train_width != 0) {
 
			int w = ScaleSpriteTrad(2 * _consistent_train_width);
src/economy.cpp
Show inline comments
 
@@ -714,49 +714,49 @@ static void CompaniesGenStatistics()
 
}
 

	
 
/**
 
 * Add monthly inflation
 
 * @param check_year Shall the inflation get stopped after 170 years?
 
 * @return true if inflation is maxed and nothing was changed
 
 */
 
bool AddInflation(bool check_year)
 
{
 
	/* The cargo payment inflation differs from the normal inflation, so the
 
	 * relative amount of money you make with a transport decreases slowly over
 
	 * the 170 years. After a few hundred years we reach a level in which the
 
	 * games will become unplayable as the maximum income will be less than
 
	 * the minimum running cost.
 
	 *
 
	 * Furthermore there are a lot of inflation related overflows all over the
 
	 * place. Solving them is hardly possible because inflation will always
 
	 * reach the overflow threshold some day. So we'll just perform the
 
	 * inflation mechanism during the first 170 years (the amount of years that
 
	 * one had in the original TTD) and stop doing the inflation after that
 
	 * because it only causes problems that can't be solved nicely and the
 
	 * inflation doesn't add anything after that either; it even makes playing
 
	 * it impossible due to the diverging cost and income rates.
 
	 */
 
	if (check_year && (TimerGameCalendar::year < ORIGINAL_BASE_YEAR || TimerGameCalendar::year >= ORIGINAL_MAX_YEAR)) return true;
 
	if (check_year && (TimerGameCalendar::year < CalendarTime::ORIGINAL_BASE_YEAR || TimerGameCalendar::year >= CalendarTime::ORIGINAL_MAX_YEAR)) return true;
 

	
 
	if (_economy.inflation_prices == MAX_INFLATION || _economy.inflation_payment == MAX_INFLATION) return true;
 

	
 
	/* Approximation for (100 + infl_amount)% ** (1 / 12) - 100%
 
	 * scaled by 65536
 
	 * 12 -> months per year
 
	 * This is only a good approximation for small values
 
	 */
 
	_economy.inflation_prices  += (_economy.inflation_prices  * _economy.infl_amount    * 54) >> 16;
 
	_economy.inflation_payment += (_economy.inflation_payment * _economy.infl_amount_pr * 54) >> 16;
 

	
 
	if (_economy.inflation_prices > MAX_INFLATION) _economy.inflation_prices = MAX_INFLATION;
 
	if (_economy.inflation_payment > MAX_INFLATION) _economy.inflation_payment = MAX_INFLATION;
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Computes all prices, payments and maximum loan.
 
 */
 
void RecomputePrices()
 
{
 
	/* Setup maximum loan as a rounded down multiple of LOAN_INTERVAL. */
 
	_economy.max_loan = ((uint64_t)_settings_game.difficulty.max_loan * _economy.inflation_prices >> 16) / LOAN_INTERVAL * LOAN_INTERVAL;
 
@@ -907,49 +907,49 @@ void StartupIndustryDailyChanges(bool in
 
	uint map_size = Map::LogX() + Map::LogY();
 
	/* After getting map size, it needs to be scaled appropriately and divided by 31,
 
	 * which stands for the days in a month.
 
	 * Using just 31 will make it so that a monthly reset (based on the real number of days of that month)
 
	 * would not be needed.
 
	 * Since it is based on "fractional parts", the leftover days will not make much of a difference
 
	 * on the overall total number of changes performed */
 
	_economy.industry_daily_increment = (1 << map_size) / 31;
 

	
 
	if (init_counter) {
 
		/* A new game or a savegame from an older version will require the counter to be initialized */
 
		_economy.industry_daily_change_counter = 0;
 
	}
 
}
 

	
 
void StartupEconomy()
 
{
 
	_economy.interest_rate = _settings_game.difficulty.initial_interest;
 
	_economy.infl_amount = _settings_game.difficulty.initial_interest;
 
	_economy.infl_amount_pr = std::max(0, _settings_game.difficulty.initial_interest - 1);
 
	_economy.fluct = GB(Random(), 0, 8) + 168;
 

	
 
	if (_settings_game.economy.inflation) {
 
		/* Apply inflation that happened before our game start year. */
 
		int months = static_cast<int32_t>(std::min(TimerGameCalendar::year, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR) * 12;
 
		int months = static_cast<int32_t>(std::min(TimerGameCalendar::year, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR) * 12;
 
		for (int i = 0; i < months; i++) {
 
			AddInflation(false);
 
		}
 
	}
 

	
 
	/* Set up prices */
 
	RecomputePrices();
 

	
 
	StartupIndustryDailyChanges(true); // As we are starting a new game, initialize the counter too
 

	
 
}
 

	
 
/**
 
 * Resets economy to initial values
 
 */
 
void InitializeEconomy()
 
{
 
	_economy.inflation_prices = _economy.inflation_payment = 1 << 16;
 
	ClearCargoPickupMonitoring();
 
	ClearCargoDeliveryMonitoring();
 
}
 

	
 
/**
 
 * Determine a certain price
src/engine.cpp
Show inline comments
 
@@ -417,49 +417,49 @@ uint Engine::GetDisplayWeight() const
 
/**
 
 * Returns the tractive effort of the engine for display purposes.
 
 * For dual-headed train-engines this is the tractive effort of both heads
 
 * @return tractive effort in display units kN
 
 */
 
uint Engine::GetDisplayMaxTractiveEffort() const
 
{
 
	/* Only trains and road vehicles have 'tractive effort'. */
 
	switch (this->type) {
 
		case VEH_TRAIN:
 
			return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
 
		case VEH_ROAD:
 
			return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Returns the vehicle's (not model's!) life length in days.
 
 * @return the life length
 
 */
 
TimerGameCalendar::Date Engine::GetLifeLengthInDays() const
 
{
 
	return DateAtStartOfYear(this->info.lifelength + _settings_game.vehicle.extend_vehicle_life);
 
	return TimerGameCalendar::DateAtStartOfYear(this->info.lifelength + _settings_game.vehicle.extend_vehicle_life);
 
}
 

	
 
/**
 
 * Get the range of an aircraft type.
 
 * @return Range of the aircraft type in tiles or 0 if unlimited range.
 
 */
 
uint16_t Engine::GetRange() const
 
{
 
	switch (this->type) {
 
		case VEH_AIRCRAFT:
 
			return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Get the name of the aircraft type for display purposes.
 
 * @return Aircraft type string.
 
 */
 
StringID Engine::GetAircraftTypeText() const
 
{
 
	switch (this->type) {
 
		case VEH_AIRCRAFT:
 
@@ -642,49 +642,49 @@ void CalcEngineReliability(Engine *e, bo
 
		e->company_avail = 0;
 
		e->reliability = e->reliability_final;
 
		/* Kick this engine out of the lists */
 
		ClearLastVariant(e->index, e->type);
 
		AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
 
	}
 

	
 
}
 

	
 
/** Compute the value for #_year_engine_aging_stops. */
 
void SetYearEngineAgingStops()
 
{
 
	/* Determine last engine aging year, default to 2050 as previously. */
 
	_year_engine_aging_stops = 2050;
 

	
 
	for (const Engine *e : Engine::Iterate()) {
 
		const EngineInfo *ei = &e->info;
 

	
 
		/* Exclude certain engines */
 
		if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
 
		if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
 

	
 
		/* Base year ending date on half the model life */
 
		TimerGameCalendar::YearMonthDay ymd;
 
		TimerGameCalendar::ConvertDateToYMD(ei->base_intro + static_cast<int32_t>(DateAtStartOfYear(ei->lifelength)) / 2, &ymd);
 
		TimerGameCalendar::ConvertDateToYMD(ei->base_intro + static_cast<int32_t>(TimerGameCalendar::DateAtStartOfYear(ei->lifelength)) / 2, &ymd);
 

	
 
		_year_engine_aging_stops = std::max(_year_engine_aging_stops, ymd.year);
 
	}
 
}
 

	
 
/**
 
 * Start/initialise one engine.
 
 * @param e The engine to initialise.
 
 * @param aging_date The date used for age calculations.
 
 * @param seed Random seed.
 
 */
 
void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t seed)
 
{
 
	const EngineInfo *ei = &e->info;
 

	
 
	e->age = 0;
 
	e->flags = 0;
 
	e->company_avail = 0;
 
	e->company_hidden = 0;
 

	
 
	/* Vehicles with the same base_intro date shall be introduced at the same time.
 
	 * Make sure they use the same randomisation of the date. */
 
	SavedRandomSeeds saved_seeds;
 
	SaveRandomSeeds(&saved_seeds);
 
@@ -1082,49 +1082,49 @@ static void NewVehicleAvailable(Engine *
 
	if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD);
 
	if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER);
 
	if (e->type == VEH_AIRCRAFT) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_AIR);
 

	
 
	/* Close pending preview windows */
 
	CloseWindowById(WC_ENGINE_PREVIEW, index);
 
}
 

	
 
/** Monthly update of the availability, reliability, and preview offers of the engines. */
 
void EnginesMonthlyLoop()
 
{
 
	if (TimerGameCalendar::year < _year_engine_aging_stops) {
 
		bool refresh = false;
 
		for (Engine *e : Engine::Iterate()) {
 
			/* Age the vehicle */
 
			if ((e->flags & ENGINE_AVAILABLE) && e->age != INT32_MAX) {
 
				e->age++;
 
				CalcEngineReliability(e, true);
 
				refresh = true;
 
			}
 

	
 
			/* Do not introduce invalid engines */
 
			if (!e->IsEnabled()) continue;
 

	
 
			if (!(e->flags & ENGINE_AVAILABLE) && TimerGameCalendar::date >= (e->intro_date + DAYS_IN_YEAR)) {
 
			if (!(e->flags & ENGINE_AVAILABLE) && TimerGameCalendar::date >= (e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
 
				/* Introduce it to all companies */
 
				NewVehicleAvailable(e);
 
			} else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && TimerGameCalendar::date >= e->intro_date) {
 
				/* Introduction date has passed...
 
				 * Check if it is allowed to build this vehicle type at all
 
				 * based on the current game settings. If not, it does not
 
				 * make sense to show the preview dialog to any company. */
 
				if (IsVehicleTypeDisabled(e->type, false)) continue;
 

	
 
				/* Do not introduce new rail wagons */
 
				if (IsWagon(e->index)) continue;
 

	
 
				/* Engine has no preview */
 
				if ((e->info.extra_flags & ExtraEngineFlags::NoPreview) != ExtraEngineFlags::None) continue;
 

	
 
				/* Show preview dialog to one of the companies. */
 
				e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
 
				e->preview_company = INVALID_COMPANY;
 
				e->preview_asked = 0;
 
			}
 
		}
 

	
 
		InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability)
 

	
src/genworld_gui.cpp
Show inline comments
 
@@ -548,79 +548,79 @@ struct GenerateLandscapeWindow : public 
 
					WID_GL_TERRAIN_PULLDOWN, WID_GL_WATER_PULLDOWN, WIDGET_LIST_END);
 
		}
 

	
 
		/* Disable snowline if not arctic */
 
		this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_TEXT, _settings_newgame.game_creation.landscape != LT_ARCTIC);
 
		/* Disable desert if not tropic */
 
		this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_TEXT, _settings_newgame.game_creation.landscape != LT_TROPIC);
 

	
 
		/* Set snow/rainforest selections */
 
		int climate_plane = 0;
 
		switch (_settings_newgame.game_creation.landscape) {
 
			case LT_TEMPERATE: climate_plane = 2; break;
 
			case LT_ARCTIC:    climate_plane = 0; break;
 
			case LT_TROPIC:    climate_plane = 1; break;
 
			case LT_TOYLAND:   climate_plane = 2; break;
 
		}
 
		this->GetWidget<NWidgetStacked>(WID_GL_CLIMATE_SEL_LABEL)->SetDisplayedPlane(climate_plane);
 
		this->GetWidget<NWidgetStacked>(WID_GL_CLIMATE_SEL_SELECTOR)->SetDisplayedPlane(climate_plane);
 

	
 
		/* Update availability of decreasing / increasing start date and snow level */
 
		if (mode == GLWM_HEIGHTMAP) {
 
			this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_DOWN, _settings_newgame.game_creation.heightmap_height <= MIN_HEIGHTMAP_HEIGHT);
 
			this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_UP, _settings_newgame.game_creation.heightmap_height >= GetMapHeightLimit());
 
		}
 
		this->SetWidgetDisabledState(WID_GL_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR);
 
		this->SetWidgetDisabledState(WID_GL_START_DATE_UP,   _settings_newgame.game_creation.starting_year >= MAX_YEAR);
 
		this->SetWidgetDisabledState(WID_GL_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= CalendarTime::MIN_YEAR);
 
		this->SetWidgetDisabledState(WID_GL_START_DATE_UP,   _settings_newgame.game_creation.starting_year >= CalendarTime::MAX_YEAR);
 
		this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_DOWN, _settings_newgame.game_creation.snow_coverage <= 0 || _settings_newgame.game_creation.landscape != LT_ARCTIC);
 
		this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_UP,   _settings_newgame.game_creation.snow_coverage >= 100 || _settings_newgame.game_creation.landscape != LT_ARCTIC);
 
		this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_DOWN, _settings_newgame.game_creation.desert_coverage <= 0 || _settings_newgame.game_creation.landscape != LT_TROPIC);
 
		this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_UP,   _settings_newgame.game_creation.desert_coverage >= 100 || _settings_newgame.game_creation.landscape != LT_TROPIC);
 

	
 
		/* Do not allow a custom sea level or terrain type with the original land generator. */
 
		if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL) {
 
			if (_settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
 
				_settings_newgame.difficulty.quantity_sea_lakes = 1;
 
			}
 
			if (_settings_newgame.difficulty.terrain_type == CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY) {
 
				_settings_newgame.difficulty.terrain_type = 1;
 
			}
 
		}
 

	
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		Dimension d{0, (uint)FONT_HEIGHT_NORMAL};
 
		const StringID *strs = nullptr;
 
		switch (widget) {
 
			case WID_GL_HEIGHTMAP_HEIGHT_TEXT:
 
				SetDParam(0, MAX_TILE_HEIGHT);
 
				d = GetStringBoundingBox(STR_JUST_INT);
 
				break;
 

	
 
			case WID_GL_START_DATE_TEXT:
 
				SetDParam(0, TimerGameCalendar::ConvertYMDToDate(MAX_YEAR, 0, 1));
 
				SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR, 0, 1));
 
				d = GetStringBoundingBox(STR_JUST_DATE_LONG);
 
				break;
 

	
 
			case WID_GL_MAPSIZE_X_PULLDOWN:
 
			case WID_GL_MAPSIZE_Y_PULLDOWN:
 
				SetDParamMaxValue(0, MAX_MAP_SIZE);
 
				d = GetStringBoundingBox(STR_JUST_INT);
 
				break;
 

	
 
			case WID_GL_SNOW_COVERAGE_TEXT:
 
				SetDParamMaxValue(0, MAX_TILE_HEIGHT);
 
				d = GetStringBoundingBox(STR_MAPGEN_SNOW_COVERAGE_TEXT);
 
				break;
 

	
 
			case WID_GL_DESERT_COVERAGE_TEXT:
 
				SetDParamMaxValue(0, MAX_TILE_HEIGHT);
 
				d = GetStringBoundingBox(STR_MAPGEN_DESERT_COVERAGE_TEXT);
 
				break;
 

	
 
			case WID_GL_HEIGHTMAP_SIZE_TEXT:
 
				SetDParam(0, this->x);
 
				SetDParam(1, this->y);
 
				d = GetStringBoundingBox(STR_MAPGEN_HEIGHTMAP_SIZE);
 
				break;
 
@@ -742,49 +742,49 @@ struct GenerateLandscapeWindow : public 
 
			case WID_GL_HEIGHTMAP_HEIGHT_UP: // Height level buttons
 
				/* Don't allow too fast scrolling */
 
				if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
 
					this->HandleButtonClick(widget);
 

	
 
					_settings_newgame.game_creation.heightmap_height = Clamp(_settings_newgame.game_creation.heightmap_height + widget - WID_GL_HEIGHTMAP_HEIGHT_TEXT, MIN_HEIGHTMAP_HEIGHT, GetMapHeightLimit());
 
					this->InvalidateData();
 
				}
 
				_left_button_clicked = false;
 
				break;
 

	
 
			case WID_GL_HEIGHTMAP_HEIGHT_TEXT: // Height level text
 
				this->widget_id = WID_GL_HEIGHTMAP_HEIGHT_TEXT;
 
				SetDParam(0, _settings_newgame.game_creation.heightmap_height);
 
				ShowQueryString(STR_JUST_INT, STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT, 4, this, CS_NUMERAL, QSF_ENABLE_DEFAULT);
 
				break;
 

	
 

	
 
			case WID_GL_START_DATE_DOWN:
 
			case WID_GL_START_DATE_UP: // Year buttons
 
				/* Don't allow too fast scrolling */
 
				if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
 
					this->HandleButtonClick(widget);
 

	
 
					_settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_GL_START_DATE_TEXT, MIN_YEAR, MAX_YEAR);
 
					_settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_GL_START_DATE_TEXT, CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
					this->InvalidateData();
 
				}
 
				_left_button_clicked = false;
 
				break;
 

	
 
			case WID_GL_START_DATE_TEXT: // Year text
 
				this->widget_id = WID_GL_START_DATE_TEXT;
 
				SetDParam(0, _settings_newgame.game_creation.starting_year);
 
				ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ENABLE_DEFAULT);
 
				break;
 

	
 
			case WID_GL_SNOW_COVERAGE_DOWN:
 
			case WID_GL_SNOW_COVERAGE_UP: // Snow coverage buttons
 
				/* Don't allow too fast scrolling */
 
				if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
 
					this->HandleButtonClick(widget);
 

	
 
					_settings_newgame.game_creation.snow_coverage = Clamp(_settings_newgame.game_creation.snow_coverage + (widget - WID_GL_SNOW_COVERAGE_TEXT) * 10, 0, 100);
 
					this->InvalidateData();
 
				}
 
				_left_button_clicked = false;
 
				break;
 

	
 
			case WID_GL_SNOW_COVERAGE_TEXT: // Snow coverage text
 
@@ -947,68 +947,68 @@ struct GenerateLandscapeWindow : public 
 
				if ((uint)index == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
 
					this->widget_id = widget;
 
					SetDParam(0, _settings_newgame.game_creation.custom_sea_level);
 
					ShowQueryString(STR_JUST_INT, STR_MAPGEN_SEA_LEVEL, 3, this, CS_NUMERAL, QSF_NONE);
 
				}
 
				_settings_newgame.difficulty.quantity_sea_lakes = index;
 
				break;
 
			}
 
		}
 
		this->InvalidateData();
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		/* Was 'cancel' pressed? */
 
		if (str == nullptr) return;
 

	
 
		int32_t value;
 
		if (!StrEmpty(str)) {
 
			value = atoi(str);
 
		} else {
 
			/* An empty string means revert to the default */
 
			switch (this->widget_id) {
 
				case WID_GL_HEIGHTMAP_HEIGHT_TEXT: value = MAP_HEIGHT_LIMIT_AUTO_MINIMUM; break;
 
				case WID_GL_START_DATE_TEXT: value = static_cast<int32_t>(DEF_START_YEAR); break;
 
				case WID_GL_START_DATE_TEXT: value = static_cast<int32_t>(CalendarTime::DEF_START_YEAR); break;
 
				case WID_GL_SNOW_COVERAGE_TEXT: value = DEF_SNOW_COVERAGE; break;
 
				case WID_GL_DESERT_COVERAGE_TEXT: value = DEF_DESERT_COVERAGE; break;
 
				case WID_GL_TOWN_PULLDOWN: value = 1; break;
 
				case WID_GL_INDUSTRY_PULLDOWN: value = 1; break;
 
				case WID_GL_TERRAIN_PULLDOWN: value = MIN_MAP_HEIGHT_LIMIT; break;
 
				case WID_GL_WATER_PULLDOWN: value = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; break;
 
				default: NOT_REACHED();
 
			}
 
		}
 

	
 
		switch (this->widget_id) {
 
			case WID_GL_HEIGHTMAP_HEIGHT_TEXT:
 
				this->SetWidgetDirty(WID_GL_HEIGHTMAP_HEIGHT_TEXT);
 
				_settings_newgame.game_creation.heightmap_height = Clamp(value, MIN_HEIGHTMAP_HEIGHT, GetMapHeightLimit());
 
				break;
 

	
 
			case WID_GL_START_DATE_TEXT:
 
				this->SetWidgetDirty(WID_GL_START_DATE_TEXT);
 
				_settings_newgame.game_creation.starting_year = Clamp(TimerGameCalendar::Year(value), MIN_YEAR, MAX_YEAR);
 
				_settings_newgame.game_creation.starting_year = Clamp(TimerGameCalendar::Year(value), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
				break;
 

	
 
			case WID_GL_SNOW_COVERAGE_TEXT:
 
				this->SetWidgetDirty(WID_GL_SNOW_COVERAGE_TEXT);
 
				_settings_newgame.game_creation.snow_coverage = Clamp(value, 0, 100);
 
				break;
 

	
 
			case WID_GL_DESERT_COVERAGE_TEXT:
 
				this->SetWidgetDirty(WID_GL_DESERT_COVERAGE_TEXT);
 
				_settings_newgame.game_creation.desert_coverage = Clamp(value, 0, 100);
 
				break;
 

	
 
			case WID_GL_TOWN_PULLDOWN:
 
				_settings_newgame.game_creation.custom_town_number = Clamp(value, 1, CUSTOM_TOWN_MAX_NUMBER);
 
				break;
 

	
 
			case WID_GL_INDUSTRY_PULLDOWN:
 
				_settings_newgame.game_creation.custom_industry_number = Clamp(value, 1, IndustryPool::MAX_SIZE);
 
				break;
 

	
 
			case WID_GL_TERRAIN_PULLDOWN:
 
				_settings_newgame.game_creation.custom_terrain_type = Clamp(value, MIN_CUSTOM_TERRAIN_TYPE, GetMapHeightLimit());
 
				break;
 

	
 
@@ -1104,67 +1104,67 @@ struct CreateScenarioWindow : public Win
 

	
 
	void SetStringParameters(int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_CS_START_DATE_TEXT:
 
				SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1));
 
				break;
 

	
 
			case WID_CS_MAPSIZE_X_PULLDOWN:
 
				SetDParam(0, 1LL << _settings_newgame.game_creation.map_x);
 
				break;
 

	
 
			case WID_CS_MAPSIZE_Y_PULLDOWN:
 
				SetDParam(0, 1LL << _settings_newgame.game_creation.map_y);
 
				break;
 

	
 
			case WID_CS_FLAT_LAND_HEIGHT_TEXT:
 
				SetDParam(0, _settings_newgame.game_creation.se_flat_world_height);
 
				break;
 
		}
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN,       _settings_newgame.game_creation.starting_year <= MIN_YEAR);
 
		this->SetWidgetDisabledState(WID_CS_START_DATE_UP,         _settings_newgame.game_creation.starting_year >= MAX_YEAR);
 
		this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN,       _settings_newgame.game_creation.starting_year <= CalendarTime::MIN_YEAR);
 
		this->SetWidgetDisabledState(WID_CS_START_DATE_UP,         _settings_newgame.game_creation.starting_year >= CalendarTime::MAX_YEAR);
 
		this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_DOWN, _settings_newgame.game_creation.se_flat_world_height <= 0);
 
		this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP,   _settings_newgame.game_creation.se_flat_world_height >= GetMapHeightLimit());
 

	
 
		this->SetWidgetLoweredState(WID_CS_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE);
 
		this->SetWidgetLoweredState(WID_CS_ARCTIC,    _settings_newgame.game_creation.landscape == LT_ARCTIC);
 
		this->SetWidgetLoweredState(WID_CS_TROPICAL,  _settings_newgame.game_creation.landscape == LT_TROPIC);
 
		this->SetWidgetLoweredState(WID_CS_TOYLAND,   _settings_newgame.game_creation.landscape == LT_TOYLAND);
 

	
 
		this->DrawWidgets();
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		StringID str = STR_JUST_INT;
 
		switch (widget) {
 
			case WID_CS_START_DATE_TEXT:
 
				SetDParam(0, TimerGameCalendar::ConvertYMDToDate(MAX_YEAR, 0, 1));
 
				SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR, 0, 1));
 
				str = STR_JUST_DATE_LONG;
 
				break;
 

	
 
			case WID_CS_MAPSIZE_X_PULLDOWN:
 
			case WID_CS_MAPSIZE_Y_PULLDOWN:
 
				SetDParamMaxValue(0, MAX_MAP_SIZE);
 
				break;
 

	
 
			case WID_CS_FLAT_LAND_HEIGHT_TEXT:
 
				SetDParamMaxValue(0, MAX_TILE_HEIGHT);
 
				break;
 

	
 
			default:
 
				return;
 
		}
 
		Dimension d = GetStringBoundingBox(str);
 
		d.width += padding.width;
 
		d.height += padding.height;
 
		*size = maxdim(*size, d);
 
	}
 

	
 
	void OnClick(Point pt, int widget, int click_count) override
 
	{
 
		switch (widget) {
 
@@ -1178,49 +1178,49 @@ struct CreateScenarioWindow : public Win
 

	
 
			case WID_CS_MAPSIZE_X_PULLDOWN: // Mapsize X
 
				ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_x, WID_CS_MAPSIZE_X_PULLDOWN);
 
				break;
 

	
 
			case WID_CS_MAPSIZE_Y_PULLDOWN: // Mapsize Y
 
				ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_y, WID_CS_MAPSIZE_Y_PULLDOWN);
 
				break;
 

	
 
			case WID_CS_EMPTY_WORLD: // Empty world / flat world
 
				StartGeneratingLandscape(GLWM_SCENARIO);
 
				break;
 

	
 
			case WID_CS_RANDOM_WORLD: // Generate
 
				ShowGenerateLandscape();
 
				break;
 

	
 
			case WID_CS_START_DATE_DOWN:
 
			case WID_CS_START_DATE_UP: // Year buttons
 
				/* Don't allow too fast scrolling */
 
				if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
 
					this->HandleButtonClick(widget);
 
					this->SetDirty();
 

	
 
					_settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_CS_START_DATE_TEXT, MIN_YEAR, MAX_YEAR);
 
					_settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_CS_START_DATE_TEXT, CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
				}
 
				_left_button_clicked = false;
 
				break;
 

	
 
			case WID_CS_START_DATE_TEXT: // Year text
 
				this->widget_id = WID_CS_START_DATE_TEXT;
 
				SetDParam(0, _settings_newgame.game_creation.starting_year);
 
				ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_NONE);
 
				break;
 

	
 
			case WID_CS_FLAT_LAND_HEIGHT_DOWN:
 
			case WID_CS_FLAT_LAND_HEIGHT_UP: // Height level buttons
 
				/* Don't allow too fast scrolling */
 
				if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) {
 
					this->HandleButtonClick(widget);
 
					this->SetDirty();
 

	
 
					_settings_newgame.game_creation.se_flat_world_height = Clamp(_settings_newgame.game_creation.se_flat_world_height + widget - WID_CS_FLAT_LAND_HEIGHT_TEXT, 0, GetMapHeightLimit());
 
				}
 
				_left_button_clicked = false;
 
				break;
 

	
 
			case WID_CS_FLAT_LAND_HEIGHT_TEXT: // Height level text
 
				this->widget_id = WID_CS_FLAT_LAND_HEIGHT_TEXT;
 
@@ -1237,49 +1237,49 @@ struct CreateScenarioWindow : public Win
 
			if (this->IsWidgetLowered(*widget)) {
 
				this->RaiseWidget(*widget);
 
				this->SetWidgetDirty(*widget);
 
			}
 
		}
 
	}
 

	
 
	void OnDropdownSelect(int widget, int index) override
 
	{
 
		switch (widget) {
 
			case WID_CS_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break;
 
			case WID_CS_MAPSIZE_Y_PULLDOWN: _settings_newgame.game_creation.map_y = index; break;
 
		}
 
		this->SetDirty();
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (!StrEmpty(str)) {
 
			int32_t value = atoi(str);
 

	
 
			switch (this->widget_id) {
 
				case WID_CS_START_DATE_TEXT:
 
					this->SetWidgetDirty(WID_CS_START_DATE_TEXT);
 
					_settings_newgame.game_creation.starting_year = Clamp(TimerGameCalendar::Year(value), MIN_YEAR, MAX_YEAR);
 
					_settings_newgame.game_creation.starting_year = Clamp(TimerGameCalendar::Year(value), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
					break;
 

	
 
				case WID_CS_FLAT_LAND_HEIGHT_TEXT:
 
					this->SetWidgetDirty(WID_CS_FLAT_LAND_HEIGHT_TEXT);
 
					_settings_newgame.game_creation.se_flat_world_height = Clamp(value, 0, GetMapHeightLimit());
 
					break;
 
			}
 

	
 
			this->SetDirty();
 
		}
 
	}
 
};
 

	
 
static const NWidgetPart _nested_create_scenario_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
 
		NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_SE_MAPGEN_CAPTION, STR_NULL),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_BROWN),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 10),
 
		/* Landscape style selection. */
 
		NWidget(NWID_HORIZONTAL), SetPIP(10, 3, 10),
 
			NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE),
 
			NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE),
src/linkgraph/flowmapper.cpp
Show inline comments
 
@@ -29,34 +29,34 @@ void FlowMapper::Run(LinkGraphJob &job) 
 
			StationID origin = job[path->GetOrigin()].base.station;
 
			assert(prev != via && via != origin);
 
			/* Mark all of the flow for local consumption at "first". */
 
			node.flows.AddFlow(origin, via, flow);
 
			if (prev != origin) {
 
				/* Pass some of the flow marked for local consumption at "prev" on
 
				 * to this node. */
 
				prev_node.flows.PassOnFlow(origin, via, flow);
 
			} else {
 
				/* Prev node is origin. Simply add flow. */
 
				prev_node.flows.AddFlow(origin, via, flow);
 
			}
 
		}
 
	}
 

	
 
	for (NodeID node_id = 0; node_id < job.Size(); ++node_id) {
 
		/* Remove local consumption shares marked as invalid. */
 
		Node &node = job[node_id];
 
		FlowStatMap &flows = node.flows;
 
		flows.FinalizeLocalConsumption(node.base.station);
 
		if (this->scale) {
 
			/* Scale by time the graph has been running without being compressed. Add 1 to avoid
 
			 * division by 0 if spawn date == last compression date. This matches
 
			 * LinkGraph::Monthly(). */
 
			auto runtime = job.JoinDate() - job.Settings().recalc_time / SECONDS_PER_DAY - job.LastCompression() + 1;
 
			auto runtime = job.JoinDate() - job.Settings().recalc_time / CalendarTime::SECONDS_PER_DAY - job.LastCompression() + 1;
 
			for (auto &it : flows) {
 
				it.second.ScaleToMonthly(static_cast<int32_t>(runtime));
 
			}
 
		}
 
		/* Clear paths. */
 
		for (Path *i : node.paths) delete i;
 
		node.paths.clear();
 
	}
 
}
src/linkgraph/linkgraph.cpp
Show inline comments
 
@@ -8,78 +8,78 @@
 
/** @file linkgraph.cpp Definition of link graph classes used for cargo distribution. */
 

	
 
#include "../stdafx.h"
 
#include "../core/pool_func.hpp"
 
#include "linkgraph.h"
 

	
 
#include "../safeguards.h"
 

	
 
/* Initialize the link-graph-pool */
 
LinkGraphPool _link_graph_pool("LinkGraph");
 
INSTANTIATE_POOL_METHODS(LinkGraph)
 

	
 
/**
 
 * Create a node or clear it.
 
 * @param xy Location of the associated station.
 
 * @param st ID of the associated station.
 
 * @param demand Demand for cargo at the station.
 
 */
 
LinkGraph::BaseNode::BaseNode(TileIndex xy, StationID st, uint demand)
 
{
 
	this->xy = xy;
 
	this->supply = 0;
 
	this->demand = demand;
 
	this->station = st;
 
	this->last_update = INVALID_DATE;
 
	this->last_update = CalendarTime::INVALID_DATE;
 
}
 

	
 
/**
 
 * Create an edge.
 
 */
 
LinkGraph::BaseEdge::BaseEdge(NodeID dest_node)
 
{
 
	this->capacity = 0;
 
	this->usage = 0;
 
	this->travel_time_sum = 0;
 
	this->last_unrestricted_update = INVALID_DATE;
 
	this->last_restricted_update = INVALID_DATE;
 
	this->last_unrestricted_update = CalendarTime::INVALID_DATE;
 
	this->last_restricted_update = CalendarTime::INVALID_DATE;
 
	this->dest_node = dest_node;
 
}
 

	
 
/**
 
 * Shift all dates by given interval.
 
 * This is useful if the date has been modified with the cheat menu.
 
 * @param interval Number of days to be added or subtracted.
 
 */
 
void LinkGraph::ShiftDates(TimerGameCalendar::Date interval)
 
{
 
	this->last_compression += interval;
 
	for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
 
		BaseNode &source = this->nodes[node1];
 
		if (source.last_update != INVALID_DATE) source.last_update += interval;
 
		if (source.last_update != CalendarTime::INVALID_DATE) source.last_update += interval;
 
		for (BaseEdge &edge : this->nodes[node1].edges) {
 
			if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
 
			if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
 
			if (edge.last_unrestricted_update != CalendarTime::INVALID_DATE) edge.last_unrestricted_update += interval;
 
			if (edge.last_restricted_update != CalendarTime::INVALID_DATE) edge.last_restricted_update += interval;
 
		}
 
	}
 
}
 

	
 
void LinkGraph::Compress()
 
{
 
	this->last_compression = static_cast<int32_t>(TimerGameCalendar::date + this->last_compression) / 2;
 
	for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
 
		this->nodes[node1].supply /= 2;
 
		for (BaseEdge &edge : this->nodes[node1].edges) {
 
			if (edge.capacity > 0) {
 
				uint new_capacity = std::max(1U, edge.capacity / 2);
 
				if (edge.capacity < (1 << 16)) {
 
					edge.travel_time_sum = edge.travel_time_sum * new_capacity / edge.capacity;
 
				} else if (edge.travel_time_sum != 0) {
 
					edge.travel_time_sum = std::max<uint64_t>(1, edge.travel_time_sum / 2);
 
				}
 
				edge.capacity = new_capacity;
 
				edge.usage /= 2;
 
			}
 
		}
 
	}
 
}
 

	
src/linkgraph/linkgraph.h
Show inline comments
 
@@ -42,50 +42,50 @@ public:
 
	 */
 
	struct BaseEdge {
 
		uint capacity;                 ///< Capacity of the link.
 
		uint usage;                    ///< Usage of the link.
 
		uint64_t travel_time_sum;        ///< Sum of the travel times of the link, in ticks.
 
		TimerGameCalendar::Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated.
 
		TimerGameCalendar::Date last_restricted_update;   ///< When the restricted part of the link was last updated.
 
		NodeID dest_node;              ///< Destination of the edge.
 

	
 
		BaseEdge(NodeID dest_node = INVALID_NODE);
 

	
 
		/**
 
		 * Get edge's average travel time.
 
		 * @return Travel time, in ticks.
 
		 */
 
		uint32_t TravelTime() const { return this->travel_time_sum / this->capacity; }
 

	
 
		/**
 
		 * Get the date of the last update to any part of the edge's capacity.
 
		 * @return Last update.
 
		 */
 
		TimerGameCalendar::Date LastUpdate() const { return std::max(this->last_unrestricted_update, this->last_restricted_update); }
 

	
 
		void Update(uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode);
 
		void Restrict() { this->last_unrestricted_update = INVALID_DATE; }
 
		void Release() { this->last_restricted_update = INVALID_DATE; }
 
		void Restrict() { this->last_unrestricted_update = CalendarTime::INVALID_DATE; }
 
		void Release() { this->last_restricted_update = CalendarTime::INVALID_DATE; }
 

	
 
		/** Comparison operator based on \c dest_node. */
 
		bool operator <(const BaseEdge &rhs) const
 
		{
 
			return this->dest_node < rhs.dest_node;
 
		}
 

	
 
		bool operator <(NodeID rhs) const
 
		{
 
			return this->dest_node < rhs;
 
		}
 

	
 
		friend inline bool operator <(NodeID lhs, const LinkGraph::BaseEdge &rhs)
 
		{
 
			return lhs < rhs.dest_node;
 
		}
 
	};
 

	
 
	/**
 
	 * Node of the link graph. contains all relevant information from the associated
 
	 * station. It's copied so that the link graph job can work on its own data set
 
	 * in a separate thread.
 
	 */
 
	struct BaseNode {
src/linkgraph/linkgraphjob.cpp
Show inline comments
 
@@ -16,49 +16,49 @@
 
#include "../safeguards.h"
 

	
 
/* Initialize the link-graph-job-pool */
 
LinkGraphJobPool _link_graph_job_pool("LinkGraphJob");
 
INSTANTIATE_POOL_METHODS(LinkGraphJob)
 

	
 
/**
 
 * Static instance of an invalid path.
 
 * Note: This instance is created on task start.
 
 *       Lazy creation on first usage results in a data race between the CDist threads.
 
 */
 
/* static */ Path *Path::invalid_path = new Path(INVALID_NODE, true);
 

	
 
/**
 
 * Create a link graph job from a link graph. The link graph will be copied so
 
 * that the calculations don't interfer with the normal operations on the
 
 * original. The job is immediately started.
 
 * @param orig Original LinkGraph to be copied.
 
 */
 
LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
 
		/* Copying the link graph here also copies its index member.
 
		 * This is on purpose. */
 
		link_graph(orig),
 
		settings(_settings_game.linkgraph),
 
		join_date(TimerGameCalendar::date + (_settings_game.linkgraph.recalc_time / SECONDS_PER_DAY)),
 
		join_date(TimerGameCalendar::date + (_settings_game.linkgraph.recalc_time / CalendarTime::SECONDS_PER_DAY)),
 
		job_completed(false),
 
		job_aborted(false)
 
{
 
}
 

	
 
/**
 
 * Erase all flows originating at a specific node.
 
 * @param from Node to erase flows for.
 
 */
 
void LinkGraphJob::EraseFlows(NodeID from)
 
{
 
	for (NodeID node_id = 0; node_id < this->Size(); ++node_id) {
 
		(*this)[node_id].flows.erase(from);
 
	}
 
}
 

	
 
/**
 
 * Spawn a thread if possible and run the link graph job in the thread. If
 
 * that's not possible run the job right now in the current thread.
 
 */
 
void LinkGraphJob::SpawnThread()
 
{
 
	if (!StartNewThread(&this->thread, "ottd:linkgraph", &(LinkGraphSchedule::Run), this)) {
 
		/* Of course this will hang a bit.
 
@@ -110,56 +110,56 @@ LinkGraphJob::~LinkGraphJob()
 
		if (st == nullptr) {
 
			this->EraseFlows(node_id);
 
			continue;
 
		}
 

	
 
		/* Link graph merging and station deletion may change around IDs. Make
 
		 * sure that everything is still consistent or ignore it otherwise. */
 
		GoodsEntry &ge = st->goods[this->Cargo()];
 
		if (ge.link_graph != this->link_graph.index || ge.node != node_id) {
 
			this->EraseFlows(node_id);
 
			continue;
 
		}
 

	
 
		LinkGraph *lg = LinkGraph::Get(ge.link_graph);
 
		FlowStatMap &flows = from.flows;
 

	
 
		for (const auto &edge : from.edges) {
 
			if (edge.Flow() == 0) continue;
 
			NodeID dest_id = edge.base.dest_node;
 
			StationID to = this->nodes[dest_id].base.station;
 
			Station *st2 = Station::GetIfValid(to);
 
			if (st2 == nullptr || st2->goods[this->Cargo()].link_graph != this->link_graph.index ||
 
					st2->goods[this->Cargo()].node != dest_id ||
 
					!(*lg)[node_id].HasEdgeTo(dest_id) ||
 
					(*lg)[node_id][dest_id].LastUpdate() == INVALID_DATE) {
 
					(*lg)[node_id][dest_id].LastUpdate() == CalendarTime::INVALID_DATE) {
 
				/* Edge has been removed. Delete flows. */
 
				StationIDStack erased = flows.DeleteFlows(to);
 
				/* Delete old flows for source stations which have been deleted
 
				 * from the new flows. This avoids flow cycles between old and
 
				 * new flows. */
 
				while (!erased.IsEmpty()) ge.flows.erase(erased.Pop());
 
			} else if ((*lg)[node_id][dest_id].last_restricted_update == INVALID_DATE) {
 
			} else if ((*lg)[node_id][dest_id].last_restricted_update == CalendarTime::INVALID_DATE) {
 
				/* Edge is fully restricted. */
 
				flows.RestrictFlows(to);
 
			}
 
		}
 

	
 
		/* Swap shares and invalidate ones that are completely deleted. Don't
 
		 * really delete them as we could then end up with unroutable cargo
 
		 * somewhere. Do delete them and also reroute relevant cargo if
 
		 * automatic distribution has been turned off for that cargo. */
 
		for (FlowStatMap::iterator it(ge.flows.begin()); it != ge.flows.end();) {
 
			FlowStatMap::iterator new_it = flows.find(it->first);
 
			if (new_it == flows.end()) {
 
				if (_settings_game.linkgraph.GetDistributionType(this->Cargo()) != DT_MANUAL) {
 
					it->second.Invalidate();
 
					++it;
 
				} else {
 
					FlowStat shares(INVALID_STATION, 1);
 
					it->second.SwapShares(shares);
 
					ge.flows.erase(it++);
 
					for (FlowStat::SharesMap::const_iterator shares_it(shares.GetShares()->begin());
 
							shares_it != shares.GetShares()->end(); ++shares_it) {
 
						RerouteCargo(st, this->Cargo(), shares_it->second, st->index);
 
					}
 
				}
src/linkgraph/linkgraphjob.h
Show inline comments
 
@@ -157,49 +157,49 @@ private:
 
	typedef std::vector<NodeAnnotation> NodeAnnotationVector;
 

	
 
	friend SaveLoadTable GetLinkGraphJobDesc();
 
	friend class LinkGraphSchedule;
 

	
 
protected:
 
	const LinkGraph link_graph;        ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
 
	const LinkGraphSettings settings;  ///< Copy of _settings_game.linkgraph at spawn time.
 
	std::thread thread;                ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
 
	TimerGameCalendar::Date join_date; ///< Date when the job is to be joined.
 
	NodeAnnotationVector nodes;        ///< Extra node data necessary for link graph calculation.
 
	std::atomic<bool> job_completed;   ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
 
	std::atomic<bool> job_aborted;     ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
 

	
 
	void EraseFlows(NodeID from);
 
	void JoinThread();
 
	void SpawnThread();
 

	
 
public:
 
	/**
 
	 * Bare constructor, only for save/load. link_graph, join_date and actually
 
	 * settings have to be brutally const-casted in order to populate them.
 
	 */
 
	LinkGraphJob() : settings(_settings_game.linkgraph),
 
			join_date(INVALID_DATE), job_completed(false), job_aborted(false) {}
 
			join_date(CalendarTime::INVALID_DATE), job_completed(false), job_aborted(false) {}
 

	
 
	LinkGraphJob(const LinkGraph &orig);
 
	~LinkGraphJob();
 

	
 
	void Init();
 

	
 
	/**
 
	 * Check if job has actually finished.
 
	 * This is allowed to spuriously return an incorrect value.
 
	 * @return True if job has actually finished.
 
	 */
 
	inline bool IsJobCompleted() const { return this->job_completed.load(std::memory_order_acquire); }
 

	
 
	/**
 
	 * Check if job has been aborted.
 
	 * This is allowed to spuriously return false incorrectly, but is not allowed to incorrectly return true.
 
	 * @return True if job has been aborted.
 
	 */
 
	inline bool IsJobAborted() const { return this->job_aborted.load(std::memory_order_acquire); }
 

	
 
	/**
 
	 * Abort job.
 
	 * The job may exit early at the next available opportunity.
 
	 * After this method has been called the state of the job is undefined, and the only valid operation
src/linkgraph/linkgraphschedule.cpp
Show inline comments
 
@@ -157,66 +157,66 @@ LinkGraphSchedule::LinkGraphSchedule()
 
LinkGraphSchedule::~LinkGraphSchedule()
 
{
 
	this->Clear();
 
	for (uint i = 0; i < lengthof(this->handlers); ++i) {
 
		delete this->handlers[i];
 
	}
 
}
 

	
 
/**
 
 * Pause the game if in 2 TimerGameCalendar::date_fract ticks, we would do a join with the next
 
 * link graph job, but it is still running.
 
 * The check is done 2 TimerGameCalendar::date_fract ticks early instead of 1, as in multiplayer
 
 * calls to DoCommandP are executed after a delay of 1 TimerGameCalendar::date_fract tick.
 
 * If we previously paused, unpause if the job is now ready to be joined with.
 
 */
 
void StateGameLoop_LinkGraphPauseControl()
 
{
 
	if (_pause_mode & PM_PAUSED_LINK_GRAPH) {
 
		/* We are paused waiting on a job, check the job every tick. */
 
		if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
			Command<CMD_PAUSE>::Post(PM_PAUSED_LINK_GRAPH, false);
 
		}
 
	} else if (_pause_mode == PM_UNPAUSED &&
 
			TimerGameCalendar::date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
 
			static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2 &&
 
			static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) / 2 &&
 
			LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
		/* Perform check two TimerGameCalendar::date_fract ticks before we would join, to make
 
		 * sure it also works in multiplayer. */
 
		Command<CMD_PAUSE>::Post(PM_PAUSED_LINK_GRAPH, true);
 
	}
 
}
 

	
 
/**
 
 * Pause the game on load if we would do a join with the next link graph job,
 
 * but it is still running, and it would not be caught by a call to
 
 * StateGameLoop_LinkGraphPauseControl().
 
 */
 
void AfterLoad_LinkGraphPauseControl()
 
{
 
	if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
 
		_pause_mode |= PM_PAUSED_LINK_GRAPH;
 
	}
 
}
 

	
 
/**
 
 * Spawn or join a link graph job or compress a link graph if any link graph is
 
 * due to do so.
 
 */
 
void OnTick_LinkGraph()
 
{
 
	if (TimerGameCalendar::date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
 
	TimerGameCalendar::Date offset = static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY);
 
	TimerGameCalendar::Date offset = static_cast<int32_t>(TimerGameCalendar::date) % (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY);
 
	if (offset == 0) {
 
		LinkGraphSchedule::instance.SpawnNext();
 
	} else if (offset == (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2) {
 
	} else if (offset == (_settings_game.linkgraph.recalc_interval / CalendarTime::SECONDS_PER_DAY) / 2) {
 
		if (!_networking || _network_server) {
 
			PerformanceMeasurer::SetInactive(PFE_GL_LINKGRAPH);
 
			LinkGraphSchedule::instance.JoinNext();
 
		} else {
 
			PerformanceMeasurer framerate(PFE_GL_LINKGRAPH);
 
			LinkGraphSchedule::instance.JoinNext();
 
		}
 
	}
 
}
 

	
 

	
src/misc_gui.cpp
Show inline comments
 
@@ -117,49 +117,49 @@ public:
 
#else
 
#	define LANDINFOD_LEVEL 1
 
#endif
 
		Debug(misc, LANDINFOD_LEVEL, "TILE: 0x{:x} ({},{})", (TileIndex)tile, TileX(tile), TileY(tile));
 
		Debug(misc, LANDINFOD_LEVEL, "type   = 0x{:x}", tile.type());
 
		Debug(misc, LANDINFOD_LEVEL, "height = 0x{:x}", tile.height());
 
		Debug(misc, LANDINFOD_LEVEL, "m1     = 0x{:x}", tile.m1());
 
		Debug(misc, LANDINFOD_LEVEL, "m2     = 0x{:x}", tile.m2());
 
		Debug(misc, LANDINFOD_LEVEL, "m3     = 0x{:x}", tile.m3());
 
		Debug(misc, LANDINFOD_LEVEL, "m4     = 0x{:x}", tile.m4());
 
		Debug(misc, LANDINFOD_LEVEL, "m5     = 0x{:x}", tile.m5());
 
		Debug(misc, LANDINFOD_LEVEL, "m6     = 0x{:x}", tile.m6());
 
		Debug(misc, LANDINFOD_LEVEL, "m7     = 0x{:x}", tile.m7());
 
		Debug(misc, LANDINFOD_LEVEL, "m8     = 0x{:x}", tile.m8());
 
#undef LANDINFOD_LEVEL
 
	}
 

	
 
	void OnInit() override
 
	{
 
		Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
 

	
 
		/* Because build_date is not set yet in every TileDesc, we make sure it is empty */
 
		TileDesc td;
 

	
 
		td.build_date = INVALID_DATE;
 
		td.build_date = CalendarTime::INVALID_DATE;
 

	
 
		/* Most tiles have only one owner, but
 
		 *  - drivethrough roadstops can be build on town owned roads (up to 2 owners) and
 
		 *  - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway").
 
		 */
 
		td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A".
 
		td.owner_type[1] = STR_NULL;       // STR_NULL results in skipping the owner
 
		td.owner_type[2] = STR_NULL;
 
		td.owner_type[3] = STR_NULL;
 
		td.owner[0] = OWNER_NONE;
 
		td.owner[1] = OWNER_NONE;
 
		td.owner[2] = OWNER_NONE;
 
		td.owner[3] = OWNER_NONE;
 

	
 
		td.station_class = STR_NULL;
 
		td.station_name = STR_NULL;
 
		td.airport_class = STR_NULL;
 
		td.airport_name = STR_NULL;
 
		td.airport_tile_name = STR_NULL;
 
		td.railtype = STR_NULL;
 
		td.rail_speed = 0;
 
		td.roadtype = STR_NULL;
 
		td.road_speed = 0;
 
		td.tramtype = STR_NULL;
 
@@ -203,49 +203,49 @@ public:
 
				SetDParam(0, cost);
 
			}
 
		}
 
		this->landinfo_data.push_back(GetString(str));
 

	
 
		/* Location */
 
		std::stringstream tile_ss;
 
		tile_ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << static_cast<uint32_t>(tile); // 0x%.4X
 

	
 
		SetDParam(0, TileX(tile));
 
		SetDParam(1, TileY(tile));
 
		SetDParam(2, GetTileZ(tile));
 
		SetDParamStr(3, tile_ss.str());
 
		this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_LANDINFO_COORDS));
 

	
 
		/* Local authority */
 
		SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE);
 
		if (t != nullptr) {
 
			SetDParam(0, STR_TOWN_NAME);
 
			SetDParam(1, t->index);
 
		}
 
		this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY));
 

	
 
		/* Build date */
 
		if (td.build_date != INVALID_DATE) {
 
		if (td.build_date != CalendarTime::INVALID_DATE) {
 
			SetDParam(0, td.build_date);
 
			this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_BUILD_DATE));
 
		}
 

	
 
		/* Station class */
 
		if (td.station_class != STR_NULL) {
 
			SetDParam(0, td.station_class);
 
			this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_STATION_CLASS));
 
		}
 

	
 
		/* Station type name */
 
		if (td.station_name != STR_NULL) {
 
			SetDParam(0, td.station_name);
 
			this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_STATION_TYPE));
 
		}
 

	
 
		/* Airport class */
 
		if (td.airport_class != STR_NULL) {
 
			SetDParam(0, td.airport_class);
 
			this->landinfo_data.push_back(GetString(STR_LAND_AREA_INFORMATION_AIRPORT_CLASS));
 
		}
 

	
 
		/* Airport name */
 
		if (td.airport_name != STR_NULL) {
src/network/core/network_game_info.cpp
Show inline comments
 
@@ -234,50 +234,48 @@ void SerializeNetworkGameInfo(Packet *p,
 
	p->Send_uint8 (info->companies_max);
 
	p->Send_uint8 (info->companies_on);
 
	p->Send_uint8 (info->clients_max); // Used to be max-spectators
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 1 */
 
	p->Send_string(info->server_name);
 
	p->Send_string(info->server_revision);
 
	p->Send_bool  (info->use_password);
 
	p->Send_uint8 (info->clients_max);
 
	p->Send_uint8 (info->clients_on);
 
	p->Send_uint8 (info->spectators_on);
 
	p->Send_uint16(info->map_width);
 
	p->Send_uint16(info->map_height);
 
	p->Send_uint8 (info->landscape);
 
	p->Send_bool  (info->dedicated);
 
}
 

	
 
/**
 
 * Deserializes the NetworkGameInfo struct from the packet.
 
 * @param p    the packet to read the data from.
 
 * @param info the NetworkGameInfo to deserialize into.
 
 */
 
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfoNewGRFLookupTable *newgrf_lookup_table)
 
{
 
	static const TimerGameCalendar::Date MAX_DATE = TimerGameCalendar::ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
 

	
 
	byte game_info_version = p->Recv_uint8();
 
	NewGRFSerializationType newgrf_serialisation = NST_GRFID_MD5;
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in game_info.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	switch (game_info_version) {
 
		case 6:
 
			newgrf_serialisation = (NewGRFSerializationType)p->Recv_uint8();
 
			if (newgrf_serialisation >= NST_END) return;
 
			FALLTHROUGH;
 

	
 
		case 5: {
 
			info->gamescript_version = (int)p->Recv_uint32();
 
			info->gamescript_name = p->Recv_string(NETWORK_NAME_LENGTH);
 
			FALLTHROUGH;
 
		}
 

	
 
		case 4: {
 
@@ -302,69 +300,69 @@ void DeserializeNetworkGameInfo(Packet *
 
					case NST_LOOKUP_ID: {
 
						if (newgrf_lookup_table == nullptr) return;
 
						auto it = newgrf_lookup_table->find(p->Recv_uint32());
 
						if (it == newgrf_lookup_table->end()) return;
 
						grf = it->second;
 
						break;
 
					}
 

	
 
					default:
 
						NOT_REACHED();
 
				}
 

	
 
				GRFConfig *c = new GRFConfig();
 
				c->ident = grf.ident;
 
				HandleIncomingNetworkGameInfoGRFConfig(c, grf.name);
 

	
 
				/* Append GRFConfig to the list */
 
				*dst = c;
 
				dst = &c->next;
 
			}
 
			FALLTHROUGH;
 
		}
 

	
 
		case 3:
 
			info->game_date      = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(MAX_DATE));
 
			info->start_date     = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(MAX_DATE));
 
			info->game_date      = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(CalendarTime::MAX_DATE));
 
			info->start_date     = Clamp(p->Recv_uint32(), 0, static_cast<int32_t>(CalendarTime::MAX_DATE));
 
			FALLTHROUGH;
 

	
 
		case 2:
 
			info->companies_max  = p->Recv_uint8 ();
 
			info->companies_on   = p->Recv_uint8 ();
 
			p->Recv_uint8(); // Used to contain max-spectators.
 
			FALLTHROUGH;
 

	
 
		case 1:
 
			info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
 
			info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
 
			if (game_info_version < 6) p->Recv_uint8 (); // Used to contain server-lang.
 
			info->use_password   = p->Recv_bool  ();
 
			info->clients_max    = p->Recv_uint8 ();
 
			info->clients_on     = p->Recv_uint8 ();
 
			info->spectators_on  = p->Recv_uint8 ();
 
			if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
 
				info->game_date    = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->start_date   = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->game_date    = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->start_date   = p->Recv_uint16() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			}
 
			if (game_info_version < 6) while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
 
			info->map_width      = p->Recv_uint16();
 
			info->map_height     = p->Recv_uint16();
 
			info->landscape      = p->Recv_uint8 ();
 
			info->dedicated      = p->Recv_bool  ();
 

	
 
			if (info->landscape >= NUM_LANDSCAPE) info->landscape = 0;
 
	}
 
}
 

	
 
/**
 
 * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
 
 * @param p    the packet to write the data to.
 
 * @param grf  the GRFIdentifier to serialize.
 
 */
 
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
 
{
 
	p->Send_uint32(grf->grfid);
 
	for (size_t j = 0; j < grf->md5sum.size(); j++) {
 
		p->Send_uint8(grf->md5sum[j]);
 
	}
 
}
 

	
src/newgrf.cpp
Show inline comments
 
@@ -975,49 +975,49 @@ static void ConvertTTDBasePrice(uint32_t
 
}
 

	
 
/** Possible return values for the FeatureChangeInfo functions */
 
enum ChangeInfoResult {
 
	CIR_SUCCESS,    ///< Variable was parsed and read
 
	CIR_DISABLED,   ///< GRF was disabled due to error
 
	CIR_UNHANDLED,  ///< Variable was parsed but unread
 
	CIR_UNKNOWN,    ///< Variable is unknown
 
	CIR_INVALID_ID, ///< Attempt to modify an invalid ID
 
};
 

	
 
typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader *buf);
 

	
 
/**
 
 * Define properties common to all vehicles
 
 * @param ei Engine info.
 
 * @param prop The property to change.
 
 * @param buf The property value.
 
 * @return ChangeInfoResult.
 
 */
 
static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader *buf)
 
{
 
	switch (prop) {
 
		case 0x00: // Introduction date
 
			ei->base_intro = buf->ReadWord() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			ei->base_intro = buf->ReadWord() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			break;
 

	
 
		case 0x02: // Decay speed
 
			ei->decay_speed = buf->ReadByte();
 
			break;
 

	
 
		case 0x03: // Vehicle life
 
			ei->lifelength = buf->ReadByte();
 
			break;
 

	
 
		case 0x04: // Model life
 
			ei->base_life = buf->ReadByte();
 
			break;
 

	
 
		case 0x06: // Climates available
 
			ei->climates = buf->ReadByte();
 
			break;
 

	
 
		case PROP_VEHICLE_LOAD_AMOUNT: // 0x07 Loading speed
 
			/* Amount of cargo loaded during a vehicle's "loading tick" */
 
			ei->load_amount = buf->ReadByte();
 
			break;
 

	
 
		default:
 
@@ -2176,49 +2176,49 @@ static ChangeInfoResult CanalChangeInfo(
 
/**
 
 * Define properties for bridges
 
 * @param brid BridgeID of the bridge.
 
 * @param numinfo Number of subsequent bridgeIDs to change the property for.
 
 * @param prop The property to change.
 
 * @param buf The property value.
 
 * @return ChangeInfoResult.
 
 */
 
static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader *buf)
 
{
 
	ChangeInfoResult ret = CIR_SUCCESS;
 

	
 
	if (brid + numinfo > MAX_BRIDGES) {
 
		GrfMsg(1, "BridgeChangeInfo: Bridge {} is invalid, max {}, ignoring", brid + numinfo, MAX_BRIDGES);
 
		return CIR_INVALID_ID;
 
	}
 

	
 
	for (int i = 0; i < numinfo; i++) {
 
		BridgeSpec *bridge = &_bridge[brid + i];
 

	
 
		switch (prop) {
 
			case 0x08: { // Year of availability
 
				/* We treat '0' as always available */
 
				byte year = buf->ReadByte();
 
				bridge->avail_year = (year > 0 ? ORIGINAL_BASE_YEAR + year : 0);
 
				bridge->avail_year = (year > 0 ? CalendarTime::ORIGINAL_BASE_YEAR + year : 0);
 
				break;
 
			}
 

	
 
			case 0x09: // Minimum length
 
				bridge->min_length = buf->ReadByte();
 
				break;
 

	
 
			case 0x0A: // Maximum length
 
				bridge->max_length = buf->ReadByte();
 
				if (bridge->max_length > 16) bridge->max_length = UINT16_MAX;
 
				break;
 

	
 
			case 0x0B: // Cost factor
 
				bridge->price = buf->ReadByte();
 
				break;
 

	
 
			case 0x0C: // Maximum speed
 
				bridge->speed = buf->ReadWord();
 
				if (bridge->speed == 0) bridge->speed = UINT16_MAX;
 
				break;
 

	
 
			case 0x0D: { // Bridge sprite tables
 
				byte tableid = buf->ReadByte();
 
				byte numtables = buf->ReadByte();
 
@@ -2236,49 +2236,49 @@ static ChangeInfoResult BridgeChangeInfo
 
					}
 

	
 
					if (bridge->sprite_table[tableid] == nullptr) {
 
						bridge->sprite_table[tableid] = MallocT<PalSpriteID>(32);
 
					}
 

	
 
					for (byte sprite = 0; sprite < 32; sprite++) {
 
						SpriteID image = buf->ReadWord();
 
						PaletteID pal  = buf->ReadWord();
 

	
 
						bridge->sprite_table[tableid][sprite].sprite = image;
 
						bridge->sprite_table[tableid][sprite].pal    = pal;
 

	
 
						MapSpriteMappingRecolour(&bridge->sprite_table[tableid][sprite]);
 
					}
 
				}
 
				break;
 
			}
 

	
 
			case 0x0E: // Flags; bit 0 - disable far pillars
 
				bridge->flags = buf->ReadByte();
 
				break;
 

	
 
			case 0x0F: // Long format year of availability (year since year 0)
 
				bridge->avail_year = Clamp(TimerGameCalendar::Year(buf->ReadDWord()), MIN_YEAR, MAX_YEAR);
 
				bridge->avail_year = Clamp(TimerGameCalendar::Year(buf->ReadDWord()), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
 
				break;
 

	
 
			case 0x10: { // purchase string
 
				StringID newone = GetGRFStringID(_cur.grffile->grfid, buf->ReadWord());
 
				if (newone != STR_UNDEFINED) bridge->material = newone;
 
				break;
 
			}
 

	
 
			case 0x11: // description of bridge with rails or roads
 
			case 0x12: {
 
				StringID newone = GetGRFStringID(_cur.grffile->grfid, buf->ReadWord());
 
				if (newone != STR_UNDEFINED) bridge->transport_name[prop - 0x11] = newone;
 
				break;
 
			}
 

	
 
			case 0x13: // 16 bits cost multiplier
 
				bridge->price = buf->ReadWord();
 
				break;
 

	
 
			default:
 
				ret = CIR_UNKNOWN;
 
				break;
 
		}
 
	}
 
@@ -2409,50 +2409,50 @@ static ChangeInfoResult TownHouseChangeI
 
					housespec->random_colour[1] = 0x08;  // for all new houses
 
					housespec->random_colour[2] = 0x0C;  // they stand for red, blue, orange and green
 
					housespec->random_colour[3] = 0x06;
 

	
 
					/* House flags 40 and 80 are exceptions; these flags are never set automatically. */
 
					housespec->building_flags &= ~(BUILDING_IS_CHURCH | BUILDING_IS_STADIUM);
 

	
 
					/* Make sure that the third cargo type is valid in this
 
					 * climate. This can cause problems when copying the properties
 
					 * of a house that accepts food, where the new house is valid
 
					 * in the temperate climate. */
 
					if (!CargoSpec::Get(housespec->accepts_cargo[2])->IsValid()) {
 
						housespec->cargo_acceptance[2] = 0;
 
					}
 
				}
 
				break;
 
			}
 

	
 
			case 0x09: // Building flags
 
				housespec->building_flags = (BuildingFlags)buf->ReadByte();
 
				break;
 

	
 
			case 0x0A: { // Availability years
 
				uint16_t years = buf->ReadWord();
 
				housespec->min_year = GB(years, 0, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 0, 8);
 
				housespec->max_year = GB(years, 8, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 8, 8);
 
				housespec->min_year = GB(years, 0, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 0, 8);
 
				housespec->max_year = GB(years, 8, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 8, 8);
 
				break;
 
			}
 

	
 
			case 0x0B: // Population
 
				housespec->population = buf->ReadByte();
 
				break;
 

	
 
			case 0x0C: // Mail generation multiplier
 
				housespec->mail_generation = buf->ReadByte();
 
				break;
 

	
 
			case 0x0D: // Passenger acceptance
 
			case 0x0E: // Mail acceptance
 
				housespec->cargo_acceptance[prop - 0x0D] = buf->ReadByte();
 
				break;
 

	
 
			case 0x0F: { // Goods/candy, food/fizzy drinks acceptance
 
				int8_t goods = buf->ReadByte();
 

	
 
				/* If value of goods is negative, it means in fact food or, if in toyland, fizzy_drink acceptance.
 
				 * Else, we have "standard" 3rd cargo type, goods or candy, for toyland once more */
 
				CargoID cid = (goods >= 0) ? ((_settings_game.game_creation.landscape == LT_TOYLAND) ? CT_CANDY : CT_GOODS) :
 
						((_settings_game.game_creation.landscape == LT_TOYLAND) ? CT_FIZZY_DRINKS : CT_FOOD);
 

	
 
@@ -3970,49 +3970,49 @@ static ChangeInfoResult AirportChangeInf
 
					}
 
					/* Free old layouts in the airport spec */
 
					for (int j = 0; j < old_num_table; j++) {
 
						/* remove the individual layouts */
 
						free(as->table[j]);
 
					}
 
					free(as->table);
 
					/* Install final layout construction in the airport spec */
 
					as->table = tile_table;
 
					free(att);
 
				} catch (...) {
 
					for (int i = 0; i < as->num_table; i++) {
 
						free(tile_table[i]);
 
					}
 
					free(tile_table);
 
					free(att);
 
					throw;
 
				}
 
				break;
 
			}
 

	
 
			case 0x0C:
 
				as->min_year = buf->ReadWord();
 
				as->max_year = buf->ReadWord();
 
				if (as->max_year == 0xFFFF) as->max_year = MAX_YEAR;
 
				if (as->max_year == 0xFFFF) as->max_year = CalendarTime::MAX_YEAR;
 
				break;
 

	
 
			case 0x0D:
 
				as->ttd_airport_type = (TTDPAirportType)buf->ReadByte();
 
				break;
 

	
 
			case 0x0E:
 
				as->catchment = Clamp(buf->ReadByte(), 1, MAX_CATCHMENT);
 
				break;
 

	
 
			case 0x0F:
 
				as->noise_level = buf->ReadByte();
 
				break;
 

	
 
			case 0x10:
 
				AddStringForMapping(buf->ReadWord(), &as->name);
 
				break;
 

	
 
			case 0x11: // Maintenance cost factor
 
				as->maintenance_cost = buf->ReadWord();
 
				break;
 

	
 
			default:
 
				ret = CIR_UNKNOWN;
 
@@ -6491,53 +6491,53 @@ static void SkipAct5(ByteReader *buf)
 
	/* Ignore type byte */
 
	buf->ReadByte();
 

	
 
	/* Skip the sprites of this action */
 
	_cur.skip_sprites = buf->ReadExtendedByte();
 

	
 
	GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur.skip_sprites);
 
}
 

	
 
/**
 
 * Reads a variable common to VarAction2 and Action7/9/D.
 
 *
 
 * Returns VarAction2 variable 'param' resp. Action7/9/D variable '0x80 + param'.
 
 * If a variable is not accessible from all four actions, it is handled in the action specific functions.
 
 *
 
 * @param param variable number (as for VarAction2, for Action7/9/D you have to subtract 0x80 first).
 
 * @param value returns the value of the variable.
 
 * @param grffile NewGRF querying the variable
 
 * @return true iff the variable is known and the value is returned in 'value'.
 
 */
 
bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile)
 
{
 
	switch (param) {
 
		case 0x00: // current date
 
			*value = static_cast<int32_t>(std::max(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)));
 
			*value = static_cast<int32_t>(std::max(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)));
 
			return true;
 

	
 
		case 0x01: // current year
 
			*value = static_cast<int32_t>(Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR);
 
			*value = static_cast<int32_t>(Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR);
 
			return true;
 

	
 
		case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24)
 
			TimerGameCalendar::YearMonthDay ymd;
 
			TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
 
			TimerGameCalendar::Date start_of_year = TimerGameCalendar::ConvertYMDToDate(ymd.year, 0, 1);
 
			*value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | static_cast<int32_t>(TimerGameCalendar::date - start_of_year) << 16;
 
			return true;
 
		}
 

	
 
		case 0x03: // current climate, 0=temp, 1=arctic, 2=trop, 3=toyland
 
			*value = _settings_game.game_creation.landscape;
 
			return true;
 

	
 
		case 0x06: // road traffic side, bit 4 clear=left, set=right
 
			*value = _settings_game.vehicle.road_side << 4;
 
			return true;
 

	
 
		case 0x09: // date fraction
 
			*value = TimerGameCalendar::date_fract * 885;
 
			return true;
 

	
 
		case 0x0A: // animation counter
 
			*value = GB(TimerGameTick::counter, 0, 16);
 
@@ -7207,49 +7207,49 @@ static void GRFComment(ByteReader *buf)
 
/* Action 0x0D (GLS_SAFETYSCAN) */
 
static void SafeParamSet(ByteReader *buf)
 
{
 
	uint8_t target = buf->ReadByte();
 

	
 
	/* Writing GRF parameters and some bits of 'misc GRF features' are safe. */
 
	if (target < 0x80 || target == 0x9E) return;
 

	
 
	/* GRM could be unsafe, but as here it can only happen after other GRFs
 
	 * are loaded, it should be okay. If the GRF tried to use the slots it
 
	 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
 
	 * sprites  is considered safe. */
 

	
 
	SetBit(_cur.grfconfig->flags, GCF_UNSAFE);
 

	
 
	/* Skip remainder of GRF */
 
	_cur.skip_sprites = -1;
 
}
 

	
 

	
 
static uint32_t GetPatchVariable(uint8_t param)
 
{
 
	switch (param) {
 
		/* start year - 1920 */
 
		case 0x0B: return static_cast<int32_t>(std::max(_settings_game.game_creation.starting_year, ORIGINAL_BASE_YEAR) - ORIGINAL_BASE_YEAR);
 
		case 0x0B: return static_cast<int32_t>(std::max(_settings_game.game_creation.starting_year, CalendarTime::ORIGINAL_BASE_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR);
 

	
 
		/* freight trains weight factor */
 
		case 0x0E: return _settings_game.vehicle.freight_trains;
 

	
 
		/* empty wagon speed increase */
 
		case 0x0F: return 0;
 

	
 
		/* plane speed factor; our patch option is reversed from TTDPatch's,
 
		 * the following is good for 1x, 2x and 4x (most common?) and...
 
		 * well not really for 3x. */
 
		case 0x10:
 
			switch (_settings_game.vehicle.plane_speed) {
 
				default:
 
				case 4: return 1;
 
				case 3: return 2;
 
				case 2: return 2;
 
				case 1: return 4;
 
			}
 

	
 

	
 
		/* 2CC colourmap base sprite */
 
		case 0x11: return SPR_2CCMAP_BASE;
 

	
 
		/* map size: format = -MABXYSS
 
@@ -9216,49 +9216,49 @@ static bool IsHouseSpecValid(HouseSpec *
 
	if (!filename.empty() && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) {
 
		hs->enabled = false;
 
		Debug(grf, 1, "FinaliseHouseArray: {} defines house {} with different house size then it's substitute type. Disabling house.", filename, hs->grf_prop.local_id);
 
		return false;
 
	}
 

	
 
	/* Make sure that additional parts of multitile houses are not available. */
 
	if ((hs->building_flags & BUILDING_HAS_1_TILE) == 0 && (hs->building_availability & HZ_ZONALL) != 0 && (hs->building_availability & HZ_CLIMALL) != 0) {
 
		hs->enabled = false;
 
		if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs->grf_prop.local_id);
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Make sure there is at least one house available in the year 0 for the given
 
 * climate / housezone combination.
 
 * @param bitmask The climate and housezone to check for. Exactly one climate
 
 *   bit and one housezone bit should be set.
 
 */
 
static void EnsureEarlyHouse(HouseZones bitmask)
 
{
 
	TimerGameCalendar::Year min_year = MAX_YEAR;
 
	TimerGameCalendar::Year min_year = CalendarTime::MAX_YEAR;
 

	
 
	for (int i = 0; i < NUM_HOUSES; i++) {
 
		HouseSpec *hs = HouseSpec::Get(i);
 
		if (hs == nullptr || !hs->enabled) continue;
 
		if ((hs->building_availability & bitmask) != bitmask) continue;
 
		if (hs->min_year < min_year) min_year = hs->min_year;
 
	}
 

	
 
	if (min_year == 0) return;
 

	
 
	for (int i = 0; i < NUM_HOUSES; i++) {
 
		HouseSpec *hs = HouseSpec::Get(i);
 
		if (hs == nullptr || !hs->enabled) continue;
 
		if ((hs->building_availability & bitmask) != bitmask) continue;
 
		if (hs->min_year == min_year) hs->min_year = 0;
 
	}
 
}
 

	
 
/**
 
 * Add all new houses to the house array. House properties can be set at any
 
 * time in the GRF file, so we can only add a house spec to the house array
 
 * after the file has finished loading. We also need to check the dates, due to
 
 * the TTDPatch behaviour described below that we need to emulate.
 
 */
src/newgrf_airport.cpp
Show inline comments
 
@@ -191,49 +191,49 @@ void AirportOverrideManager::SetEntitySp
 

	
 
		overridden_as->grf_prop.override = airport_id;
 
		overridden_as->enabled = false;
 
		this->entity_overrides[i] = this->invalid_id;
 
		this->grfid_overrides[i] = 0;
 
	}
 
}
 

	
 
/* virtual */ uint32_t AirportScopeResolver::GetVariable(byte variable, uint32_t parameter, bool *available) const
 
{
 
	switch (variable) {
 
		case 0x40: return this->layout;
 
	}
 

	
 
	if (this->st == nullptr) {
 
		*available = false;
 
		return UINT_MAX;
 
	}
 

	
 
	switch (variable) {
 
		/* Get a variable from the persistent storage */
 
		case 0x7C: return (this->st->airport.psa != nullptr) ? this->st->airport.psa->GetValue(parameter) : 0;
 

	
 
		case 0xF0: return this->st->facilities;
 
		case 0xFA: return ClampTo<uint16_t>(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR);
 
		case 0xFA: return ClampTo<uint16_t>(this->st->build_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
 
	}
 

	
 
	return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
 
}
 

	
 
GrfSpecFeature AirportResolverObject::GetFeature() const
 
{
 
	return GSF_AIRPORTS;
 
}
 

	
 
uint32_t AirportResolverObject::GetDebugID() const
 
{
 
	return AirportSpec::Get(this->airport_scope.airport_id)->grf_prop.local_id;
 
}
 

	
 
/* virtual */ uint32_t AirportScopeResolver::GetRandomBits() const
 
{
 
	return this->st == nullptr ? 0 : this->st->random_bits;
 
}
 

	
 
/**
 
 * Store a value into the object's persistent storage.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
src/newgrf_engine.cpp
Show inline comments
 
@@ -746,50 +746,50 @@ static uint32_t VehicleGetVariable(Vehic
 
		case 0x06: break; // not implemented
 
		case 0x07: break; // not implemented
 
		case 0x08: break; // not implemented
 
		case 0x09: break; // not implemented
 
		case 0x0A: return v->current_order.MapOldOrder();
 
		case 0x0B: return v->current_order.GetDestination();
 
		case 0x0C: return v->GetNumOrders();
 
		case 0x0D: return v->cur_real_order_index;
 
		case 0x0E: break; // not implemented
 
		case 0x0F: break; // not implemented
 
		case 0x10:
 
		case 0x11: {
 
			uint ticks;
 
			if (v->current_order.IsType(OT_LOADING)) {
 
				ticks = v->load_unload_ticks;
 
			} else {
 
				switch (v->type) {
 
					case VEH_TRAIN:    ticks = Train::From(v)->wait_counter; break;
 
					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_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 0x12: return ClampTo<uint16_t>(v->date_of_last_service_newgrf - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
 
		case 0x13: return GB(ClampTo<uint16_t>(v->date_of_last_service_newgrf - CalendarTime::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: {
 
			uint max_speed;
 
			switch (v->type) {
 
				case VEH_AIRCRAFT:
 
					max_speed = Aircraft::From(v)->GetSpeedOldUnits(); // Convert to old units.
 
					break;
 

	
 
				default:
 
					max_speed = v->vcache.cached_max_speed;
 
					break;
 
			}
 
			return (variable - 0x80) == 0x18 ? max_speed : GB(max_speed, 8, 8);
 
		}
 
		case 0x1A: return v->x_pos;
 
		case 0x1B: return GB(v->x_pos, 8, 8);
 
		case 0x1C: return v->y_pos;
 
		case 0x1D: return GB(v->y_pos, 8, 8);
 
		case 0x1E: return v->z_pos;
 
		case 0x1F: return object->rotor_in_gui ? DIR_W : v->direction; // for rotors the spriteset contains animation frames, so NewGRF need a different way to tell the helicopter orientation.
 
@@ -808,49 +808,49 @@ static uint32_t VehicleGetVariable(Vehic
 
		case 0x2C: break; // not implemented
 
		case 0x2D: break; // not implemented
 
		case 0x2E: break; // not implemented
 
		case 0x2F: break; // not implemented
 
		case 0x30: break; // not implemented
 
		case 0x31: break; // not implemented
 
		case 0x32: return v->vehstatus;
 
		case 0x33: return 0; // non-existent high byte of vehstatus
 
		case 0x34: return v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed;
 
		case 0x35: return GB(v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed, 8, 8);
 
		case 0x36: return v->subspeed;
 
		case 0x37: return v->acceleration;
 
		case 0x38: break; // not implemented
 
		case 0x39: return v->cargo_type;
 
		case 0x3A: return v->cargo_cap;
 
		case 0x3B: return GB(v->cargo_cap, 8, 8);
 
		case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount());
 
		case 0x3D: return GB(ClampTo<uint16_t>(v->cargo.StoredCount()), 8, 8);
 
		case 0x3E: return v->cargo.GetFirstStation();
 
		case 0x3F: return ClampTo<uint8_t>(v->cargo.PeriodsInTransit());
 
		case 0x40: return ClampTo<uint16_t>(v->age);
 
		case 0x41: return GB(ClampTo<uint16_t>(v->age), 8, 8);
 
		case 0x42: return ClampTo<uint16_t>(v->max_age);
 
		case 0x43: return GB(ClampTo<uint16_t>(v->max_age), 8, 8);
 
		case 0x44: return static_cast<int32_t>(Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR);
 
		case 0x44: return static_cast<int32_t>(Clamp(v->build_year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR);
 
		case 0x45: return v->unitnumber;
 
		case 0x46: return v->GetEngine()->grf_prop.local_id;
 
		case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8);
 
		case 0x48:
 
			if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum;
 
			return HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD;
 

	
 
		case 0x49: return v->day_counter;
 
		case 0x4A: return v->breakdowns_since_last_service;
 
		case 0x4B: return v->breakdown_ctr;
 
		case 0x4C: return v->breakdown_delay;
 
		case 0x4D: return v->breakdown_chance;
 
		case 0x4E: return v->reliability;
 
		case 0x4F: return GB(v->reliability, 8, 8);
 
		case 0x50: return v->reliability_spd_dec;
 
		case 0x51: return GB(v->reliability_spd_dec, 8, 8);
 
		case 0x52: return ClampTo<int32_t>(v->GetDisplayProfitThisYear());
 
		case 0x53: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()),  8, 24);
 
		case 0x54: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 16, 16);
 
		case 0x55: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 24,  8);
 
		case 0x56: return ClampTo<int32_t>(v->GetDisplayProfitLastYear());
 
		case 0x57: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()),  8, 24);
 
		case 0x58: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 16, 16);
 
		case 0x59: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 24,  8);
 
@@ -953,51 +953,51 @@ static uint32_t VehicleGetVariable(Vehic
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
/* virtual */ uint32_t VehicleScopeResolver::GetVariable(byte variable, uint32_t parameter, bool *available) const
 
{
 
	if (this->v == nullptr) {
 
		/* Vehicle does not exist, so we're in a purchase list */
 
		switch (variable) {
 
			case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, nullptr)); // Owner information
 
			case 0x46: return 0;               // Motion counter
 
			case 0x47: { // Vehicle cargo info
 
				const Engine *e = Engine::Get(this->self_type);
 
				CargoID cargo_type = e->GetDefaultCargoType();
 
				if (IsValidCargoID(cargo_type)) {
 
					const CargoSpec *cs = CargoSpec::Get(cargo_type);
 
					return (cs->classes << 16) | (cs->weight << 8) | this->ro.grffile->cargo_map[cargo_type];
 
				} else {
 
					return 0x000000FF;
 
				}
 
			}
 
			case 0x48: return Engine::Get(this->self_type)->flags; // Vehicle Type Info
 
			case 0x49: return static_cast<int32_t>(TimerGameCalendar::year); // 'Long' format build year
 
			case 0x4B: return static_cast<int32_t>(TimerGameCalendar::date); // Long date of last service
 
			case 0x92: return ClampTo<uint16_t>(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date of last service
 
			case 0x93: return GB(ClampTo<uint16_t>(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
 
			case 0xC4: return static_cast<int32_t>(Clamp(TimerGameCalendar::year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR); // Build year
 
			case 0x92: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date of last service
 
			case 0x93: return GB(ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
 
			case 0xC4: return static_cast<int32_t>(Clamp(TimerGameCalendar::year, CalendarTime::ORIGINAL_BASE_YEAR, CalendarTime::ORIGINAL_MAX_YEAR) - CalendarTime::ORIGINAL_BASE_YEAR); // Build year
 
			case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
 
			case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
 
			case 0xDA: return INVALID_VEHICLE; // Next vehicle
 
			case 0xF2: return 0; // Cargo subtype
 
		}
 

	
 
		*available = false;
 
		return UINT_MAX;
 
	}
 

	
 
	return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, available);
 
}
 

	
 

	
 
/* virtual */ const SpriteGroup *VehicleResolverObject::ResolveReal(const RealSpriteGroup *group) const
 
{
 
	const Vehicle *v = this->self_scope.v;
 

	
 
	if (v == nullptr) {
 
		if (!group->loading.empty()) return group->loading[0];
 
		if (!group->loaded.empty())  return group->loaded[0];
 
		return nullptr;
 
	}
 

	
src/newgrf_industries.cpp
Show inline comments
 
@@ -375,58 +375,58 @@ static uint32_t GetCountAndDistanceOfClo
 
		case 0x96: return this->industry->produced[1].history[THIS_MONTH].production;
 
		case 0x97: return GB(this->industry->produced[1].history[THIS_MONTH].production, 8, 8);
 
		/* amount of cargo transported so far THIS month. */
 
		case 0x98: return this->industry->produced[0].history[THIS_MONTH].transported;
 
		case 0x99: return GB(this->industry->produced[0].history[THIS_MONTH].transported, 8, 8);
 
		case 0x9A: return this->industry->produced[1].history[THIS_MONTH].transported;
 
		case 0x9B: return GB(this->industry->produced[1].history[THIS_MONTH].transported, 8, 8);
 
		/* fraction of cargo transported LAST month. */
 
		case 0x9C:
 
		case 0x9D: return this->industry->produced[variable - 0x9C].history[LAST_MONTH].PctTransported();
 
		/* amount of cargo produced LAST month. */
 
		case 0x9E: return this->industry->produced[0].history[LAST_MONTH].production;
 
		case 0x9F: return GB(this->industry->produced[0].history[LAST_MONTH].production, 8, 8);
 
		case 0xA0: return this->industry->produced[1].history[LAST_MONTH].production;
 
		case 0xA1: return GB(this->industry->produced[1].history[LAST_MONTH].production, 8, 8);
 
		/* amount of cargo transported last month. */
 
		case 0xA2: return this->industry->produced[0].history[LAST_MONTH].transported;
 
		case 0xA3: return GB(this->industry->produced[0].history[LAST_MONTH].transported, 8, 8);
 
		case 0xA4: return this->industry->produced[1].history[LAST_MONTH].transported;
 
		case 0xA5: return GB(this->industry->produced[1].history[LAST_MONTH].transported, 8, 8);
 

	
 
		case 0xA6: return indspec->grf_prop.local_id;
 
		case 0xA7: return this->industry->founder;
 
		case 0xA8: return this->industry->random_colour;
 
		case 0xA9: return ClampTo<uint8_t>(this->industry->last_prod_year - ORIGINAL_BASE_YEAR);
 
		case 0xA9: return ClampTo<uint8_t>(this->industry->last_prod_year - CalendarTime::ORIGINAL_BASE_YEAR);
 
		case 0xAA: return this->industry->counter;
 
		case 0xAB: return GB(this->industry->counter, 8, 8);
 
		case 0xAC: return this->industry->was_cargo_delivered;
 

	
 
		case 0xB0: return ClampTo<uint16_t>(this->industry->construction_date - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date when built since 1920 (in days)
 
		case 0xB0: return ClampTo<uint16_t>(this->industry->construction_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date when built since 1920 (in days)
 
		case 0xB3: return this->industry->construction_type; // Construction type
 
		case 0xB4: {
 
			auto it = std::max_element(std::begin(this->industry->accepted), std::end(this->industry->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
 
			return ClampTo<uint16_t>(it->last_accepted - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
 
			return ClampTo<uint16_t>(it->last_accepted - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
 
		}
 
	}
 

	
 
	Debug(grf, 1, "Unhandled industry variable 0x{:X}", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
/* virtual */ uint32_t IndustriesScopeResolver::GetRandomBits() const
 
{
 
	return this->industry != nullptr ? this->industry->random : 0;
 
}
 

	
 
/* virtual */ uint32_t IndustriesScopeResolver::GetTriggers() const
 
{
 
	return 0;
 
}
 

	
 
/* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32_t value)
 
{
 
	if (this->industry->index == INVALID_INDUSTRY) return;
 

	
 
	if (this->industry->psa == nullptr) {
src/newgrf_roadstop.cpp
Show inline comments
 
@@ -152,49 +152,49 @@ uint32_t RoadStopScopeResolver::GetVaria
 
			if (type == STATION_TRUCK) res |= (1 << 16);
 
			if (type == this->type) SetBit(res, 20);
 

	
 
			if (IsCustomRoadStopSpecIndex(nearby_tile)) {
 
				const RoadStopSpecList ssl = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
 
				res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(ssl.localidx);
 
			}
 
			return res;
 
		}
 

	
 
		/* GRFID of nearby road stop tiles */
 
		case 0x6A: {
 
			if (this->tile == INVALID_TILE) return 0xFFFFFFFF;
 
			TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
 

	
 
			if (!IsRoadStopTile(nearby_tile)) return 0xFFFFFFFF;
 
			if (!IsCustomRoadStopSpecIndex(nearby_tile)) return 0;
 

	
 
			const RoadStopSpecList ssl = BaseStation::GetByTile(nearby_tile)->roadstop_speclist[GetCustomRoadStopSpecIndex(nearby_tile)];
 
			return ssl.grfid;
 
		}
 

	
 
		case 0xF0: return this->st == nullptr ? 0 : this->st->facilities; // facilities
 

	
 
		case 0xFA: return ClampTo<uint16_t>((this->st == nullptr ? TimerGameCalendar::date : this->st->build_date) - DAYS_TILL_ORIGINAL_BASE_YEAR); // build date
 
		case 0xFA: return ClampTo<uint16_t>((this->st == nullptr ? TimerGameCalendar::date : this->st->build_date) - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // build date
 
	}
 

	
 
	if (this->st != nullptr) return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
const SpriteGroup *RoadStopResolverObject::ResolveReal(const RealSpriteGroup *group) const
 
{
 
	if (group == nullptr) return nullptr;
 

	
 
	return group->loading[0];
 
}
 

	
 
RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, RoadType roadtype, StationType type, uint8_t view,
 
		CallbackID callback, uint32_t param1, uint32_t param2)
 
	: ResolverObject(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, roadtype, type, view)
 
	{
 

	
 
	this->town_scope = nullptr;
 

	
 
	CargoID ctype = CT_DEFAULT_NA;
 

	
src/newgrf_station.cpp
Show inline comments
 
@@ -270,49 +270,49 @@ TownScopeResolver *StationResolverObject
 
{
 
	if (this->st == nullptr) {
 
		/* Station does not exist, so we're in a purchase list or the land slope check callback. */
 
		switch (variable) {
 
			case 0x40:
 
			case 0x41:
 
			case 0x46:
 
			case 0x47:
 
			case 0x49: return 0x2110000;        // Platforms, tracks & position
 
			case 0x42: return 0;                // Rail type (XXX Get current type from GUI?)
 
			case 0x43: return GetCompanyInfo(_current_company); // Station owner
 
			case 0x44: return 2;                // PBS status
 
			case 0x67: // Land info of nearby tile
 
				if (this->axis != INVALID_AXIS && this->tile != INVALID_TILE) {
 
					TileIndex tile = this->tile;
 
					if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required
 

	
 
					Slope tileh = GetTileSlope(tile);
 
					bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
 

	
 
					return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
 
				}
 
				break;
 

	
 
			case 0xFA: return ClampTo<uint16_t>(TimerGameCalendar::date - DAYS_TILL_ORIGINAL_BASE_YEAR); // Build date, clamped to a 16 bit value
 
			case 0xFA: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Build date, clamped to a 16 bit value
 
		}
 

	
 
		*available = false;
 
		return UINT_MAX;
 
	}
 

	
 
	switch (variable) {
 
		/* Calculated station variables */
 
		case 0x40:
 
			if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(this->tile, false, false, false); SetBit(_svc.valid, 0); }
 
			return _svc.v40;
 

	
 
		case 0x41:
 
			if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(this->tile, true,  false, false); SetBit(_svc.valid, 1); }
 
			return _svc.v41;
 

	
 
		case 0x42: return GetTerrainType(this->tile) | (GetReverseRailTypeTranslation(GetRailType(this->tile), this->statspec->grf_prop.grffile) << 8);
 
		case 0x43: return GetCompanyInfo(this->st->owner); // Station owner
 
		case 0x44: return HasStationReservation(this->tile) ? 7 : 4; // PBS status
 
		case 0x45:
 
			if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(this->tile); SetBit(_svc.valid, 2); }
 
			return _svc.v45;
 

	
 
		case 0x46:
 
@@ -360,49 +360,49 @@ TownScopeResolver *StationResolverObject
 
			uint32_t res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
 

	
 
			if (IsCustomStationSpecIndex(nearby_tile)) {
 
				const StationSpecList ssl = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
 
				res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ClampTo<uint8_t>(ssl.localidx);
 
			}
 
			return res;
 
		}
 

	
 
		case 0x6A: { // GRFID of nearby station tiles
 
			TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
 

	
 
			if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
 
			if (!IsCustomStationSpecIndex(nearby_tile)) return 0;
 

	
 
			const StationSpecList ssl = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
 
			return ssl.grfid;
 
		}
 

	
 
		/* General station variables */
 
		case 0x82: return 50;
 
		case 0x84: return this->st->string_id;
 
		case 0x86: return 0;
 
		case 0xF0: return this->st->facilities;
 
		case 0xFA: return ClampTo<uint16_t>(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR);
 
		case 0xFA: return ClampTo<uint16_t>(this->st->build_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
 
	}
 

	
 
	return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
 
}
 

	
 
uint32_t Station::GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const
 
{
 
	switch (variable) {
 
		case 0x48: { // Accepted cargo types
 
			CargoID cargo_type;
 
			uint32_t value = 0;
 

	
 
			for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
 
				if (HasBit(this->goods[cargo_type].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(value, cargo_type);
 
			}
 
			return value;
 
		}
 

	
 
		case 0x8A: return this->had_vehicle_of_type;
 
		case 0xF1: return (this->airport.tile != INVALID_TILE) ? this->airport.GetSpec()->ttd_airport_type : ATP_TTDP_LARGE;
 
		case 0xF2: return (this->truck_stops != nullptr) ? this->truck_stops->status : 0;
 
		case 0xF3: return (this->bus_stops != nullptr)   ? this->bus_stops->status   : 0;
 
		case 0xF6: return this->airport.flags;
 
		case 0xF7: return GB(this->airport.flags, 8, 8);
src/newgrf_text.cpp
Show inline comments
 
@@ -2,48 +2,49 @@
 
 * This file is part of OpenTTD.
 
 * 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.
 
 * 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.
 
 * 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/>.
 
 */
 

	
 
/**
 
 * @file newgrf_text.cpp
 
 * Implementation of  Action 04 "universal holder" structure and functions.
 
 * This file implements a linked-lists of strings,
 
 * holding everything that the newgrf action 04 will send over to OpenTTD.
 
 * One of the biggest problems is that Dynamic lang Array uses ISO codes
 
 * as way to identifying current user lang, while newgrf uses bit shift codes
 
 * not related to ISO.  So equivalence functionality had to be set.
 
 */
 

	
 
#include "stdafx.h"
 

	
 
#include "newgrf.h"
 
#include "strings_internal.h"
 
#include "newgrf_storage.h"
 
#include "newgrf_text.h"
 
#include "newgrf_cargo.h"
 
#include "string_func.h"
 
#include "timer/timer_game_calendar.h"
 
#include "date_type.h"
 
#include "debug.h"
 
#include "core/alloc_type.hpp"
 
#include "language.h"
 
#include <sstream>
 

	
 
#include "table/strings.h"
 
#include "table/control_codes.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Explains the newgrf shift bit positioning.
 
 * the grf base will not be used in order to find the string, but rather for
 
 * jumping from standard langID scheme to the new one.
 
 */
 
enum GRFBaseLanguages {
 
	GRFLB_AMERICAN    = 0x01,
 
	GRFLB_ENGLISH     = 0x02,
 
	GRFLB_GERMAN      = 0x04,
 
	GRFLB_FRENCH      = 0x08,
 
	GRFLB_SPANISH     = 0x10,
 
	GRFLB_GENERIC     = 0x80,
 
};
 
@@ -891,49 +892,49 @@ uint RemapNewGRFStringControlCode(uint s
 
			case SCC_NEWGRF_PRINT_DWORD_SIGNED:     parameters.SetParam(0, _newgrf_textrefstack.PopSignedDWord());   break;
 

	
 
			case SCC_NEWGRF_PRINT_BYTE_HEX:         parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedByte());  break;
 
			case SCC_NEWGRF_PRINT_QWORD_HEX:        parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedQWord()); break;
 

	
 
			case SCC_NEWGRF_PRINT_WORD_SPEED:
 
			case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
 
			case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
 
			case SCC_NEWGRF_PRINT_WORD_SIGNED:      parameters.SetParam(0, _newgrf_textrefstack.PopSignedWord());    break;
 

	
 
			case SCC_NEWGRF_PRINT_WORD_HEX:
 
			case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
 
			case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
 
			case SCC_NEWGRF_PRINT_WORD_POWER:
 
			case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
 
			case SCC_NEWGRF_PRINT_WORD_UNSIGNED:    parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord());  break;
 

	
 
			case SCC_NEWGRF_PRINT_DWORD_FORCE:
 
			case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
 
			case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
 
			case SCC_NEWGRF_PRINT_DWORD_HEX:        parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedDWord()); break;
 

	
 
			/* Dates from NewGRFs have 1920-01-01 as their zero point, convert it to OpenTTD's epoch. */
 
			case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
 
			case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:  parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR); break;
 
			case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:  parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord() + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); break;
 

	
 
			case SCC_NEWGRF_DISCARD_WORD:           _newgrf_textrefstack.PopUnsignedWord(); break;
 

	
 
			case SCC_NEWGRF_ROTATE_TOP_4_WORDS:     _newgrf_textrefstack.RotateTop4Words(); break;
 
			case SCC_NEWGRF_PUSH_WORD:              _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
 

	
 
			case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
 
			case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
 
			case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
 
				parameters.SetParam(0, GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile));
 
				parameters.SetParam(1, _newgrf_textrefstack.PopUnsignedWord());
 
				break;
 

	
 
			case SCC_NEWGRF_PRINT_WORD_STRING_ID:
 
				parameters.SetParam(0, MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord()));
 
				break;
 

	
 
			case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
 
				CargoID cargo = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
 
				parameters.SetParam(0, cargo < NUM_CARGO ? 1ULL << cargo : 0);
 
				break;
 
			}
 
		}
 
	} else {
src/news_gui.cpp
Show inline comments
 
@@ -1113,49 +1113,49 @@ static void DrawNewsString(uint left, ui
 
}
 

	
 
struct MessageHistoryWindow : Window {
 
	int line_height; /// < Height of a single line in the news history window including spacing.
 
	int date_width;  /// < Width needed for the date part.
 

	
 
	Scrollbar *vscroll;
 

	
 
	MessageHistoryWindow(WindowDesc *desc) : Window(desc)
 
	{
 
		this->CreateNestedTree();
 
		this->vscroll = this->GetScrollbar(WID_MH_SCROLLBAR);
 
		this->FinishInitNested(); // Initializes 'this->line_height' and 'this->date_width'.
 
		this->OnInvalidateData(0);
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		if (widget == WID_MH_BACKGROUND) {
 
			this->line_height = FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
 
			resize->height = this->line_height;
 

	
 
			/* Months are off-by-one, so it's actually 8. Not using
 
			 * month 12 because the 1 is usually less wide. */
 
			SetDParam(0, TimerGameCalendar::ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30));
 
			SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::ORIGINAL_MAX_YEAR, 7, 30));
 
			this->date_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width + WidgetDimensions::scaled.hsep_wide;
 

	
 
			size->height = 4 * resize->height + WidgetDimensions::scaled.framerect.Vertical(); // At least 4 lines are visible.
 
			size->width = std::max(200u, size->width); // At least 200 pixels wide.
 
		}
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		this->OnInvalidateData(0);
 
		this->DrawWidgets();
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		if (widget != WID_MH_BACKGROUND || _total_news == 0) return;
 

	
 
		/* Find the first news item to display. */
 
		NewsItem *ni = _latest_news;
 
		for (int n = this->vscroll->GetPosition(); n > 0; n--) {
 
			ni = ni->prev;
 
			if (ni == nullptr) return;
 
		}
 

	
src/openttd.cpp
Show inline comments
 
@@ -359,98 +359,98 @@ void MakeNewgameSettingsLive()
 
		_settings_game.ai_config[c] = nullptr;
 
		if (_settings_newgame.ai_config[c] != nullptr) {
 
			_settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]);
 
			if (!AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->HasScript()) {
 
				AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(std::nullopt);
 
			}
 
		}
 
	}
 
	_settings_game.game_config = nullptr;
 
	if (_settings_newgame.game_config != nullptr) {
 
		_settings_game.game_config = new GameConfig(_settings_newgame.game_config);
 
	}
 
}
 

	
 
void OpenBrowser(const char *url)
 
{
 
	/* Make sure we only accept urls that are sure to open a browser. */
 
	if (StrStartsWith(url, "http://") || StrStartsWith(url, "https://")) {
 
		OSOpenBrowser(url);
 
	}
 
}
 

	
 
/** Callback structure of statements to be executed after the NewGRF scan. */
 
struct AfterNewGRFScan : NewGRFScanCallback {
 
	TimerGameCalendar::Year startyear = INVALID_YEAR; ///< The start year.
 
	TimerGameCalendar::Year startyear = CalendarTime::INVALID_YEAR; ///< The start year.
 
	uint32_t generation_seed = GENERATE_NEW_SEED; ///< Seed for the new game.
 
	std::string dedicated_host;                 ///< Hostname for the dedicated server.
 
	uint16_t dedicated_port = 0;                  ///< Port for the dedicated server.
 
	std::string connection_string;              ///< Information about the server to connect to
 
	std::string join_server_password;           ///< The password to join the server with.
 
	std::string join_company_password;          ///< The password to join the company with.
 
	bool save_config = true;                    ///< The save config setting.
 

	
 
	/**
 
	 * Create a new callback.
 
	 */
 
	AfterNewGRFScan()
 
	{
 
		/* Visual C++ 2015 fails compiling this line (AfterNewGRFScan::generation_seed undefined symbol)
 
		 * if it's placed outside a member function, directly in the struct body. */
 
		static_assert(sizeof(generation_seed) == sizeof(_settings_game.game_creation.generation_seed));
 
	}
 

	
 
	virtual void OnNewGRFsScanned()
 
	{
 
		ResetGRFConfig(false);
 

	
 
		TarScanner::DoScan(TarScanner::SCENARIO);
 

	
 
		AI::Initialize();
 
		Game::Initialize();
 

	
 
		/* We want the new (correct) NewGRF count to survive the loading. */
 
		uint last_newgrf_count = _settings_client.gui.last_newgrf_count;
 
		LoadFromConfig();
 
		_settings_client.gui.last_newgrf_count = last_newgrf_count;
 
		/* Since the default for the palette might have changed due to
 
		 * reading the configuration file, recalculate that now. */
 
		UpdateNewGRFConfigPalette();
 

	
 
		Game::Uninitialize(true);
 
		AI::Uninitialize(true);
 
		LoadFromHighScore();
 
		LoadHotkeysFromConfig();
 
		WindowDesc::LoadFromConfig();
 

	
 
		/* We have loaded the config, so we may possibly save it. */
 
		_save_config = save_config;
 

	
 
		/* restore saved music and effects volumes */
 
		MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol);
 
		SetEffectVolume(_settings_client.music.effect_vol);
 

	
 
		if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", static_cast<int32_t>(startyear));
 
		if (startyear != CalendarTime::INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", static_cast<int32_t>(startyear));
 
		if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed;
 

	
 
		if (!dedicated_host.empty()) {
 
			_network_bind_list.clear();
 
			_network_bind_list.emplace_back(dedicated_host);
 
		}
 
		if (dedicated_port != 0) _settings_client.network.server_port = dedicated_port;
 

	
 
		/* initialize the ingame console */
 
		IConsoleInit();
 
		InitializeGUI();
 
		IConsoleCmdExec("exec scripts/autoexec.scr 0");
 

	
 
		/* Make sure _settings is filled with _settings_newgame if we switch to a game directly */
 
		if (_switch_mode != SM_NONE) MakeNewgameSettingsLive();
 

	
 
		if (_network_available && !connection_string.empty()) {
 
			LoadIntroGame();
 
			_switch_mode = SM_NONE;
 

	
 
			NetworkClientConnectGame(connection_string, COMPANY_NEW_COMPANY, join_server_password, join_company_password);
 
		}
 

	
 
		/* After the scan we're not used anymore. */
src/order_base.h
Show inline comments
 
@@ -346,50 +346,50 @@ public:
 
	inline Vehicle *GetFirstSharedVehicle() const { return this->first_shared; }
 

	
 
	/**
 
	 * Return the number of vehicles that share this orders list
 
	 * @return the count of vehicles that use this shared orders list
 
	 */
 
	inline uint GetNumVehicles() const { return this->num_vehicles; }
 

	
 
	bool IsVehicleInSharedOrdersList(const Vehicle *v) const;
 
	int GetPositionInSharedOrderList(const Vehicle *v) const;
 

	
 
	/**
 
	 * Adds the given vehicle to this shared order list.
 
	 * @note This is supposed to be called after the vehicle has been inserted
 
	 *       into the shared vehicle chain.
 
	 * @param v vehicle to add to the list
 
	 */
 
	inline void AddVehicle(Vehicle *v) { ++this->num_vehicles; }
 

	
 
	void RemoveVehicle(Vehicle *v);
 

	
 
	bool IsCompleteTimetable() const;
 

	
 
	/**
 
	 * Gets the total duration of the vehicles timetable or Tick::INVALID_TICKS is the timetable is not complete.
 
	 * @return total timetable duration or Tick::INVALID_TICKS for incomplete timetables
 
	 * Gets the total duration of the vehicles timetable or Ticks::INVALID_TICKS is the timetable is not complete.
 
	 * @return total timetable duration or Ticks::INVALID_TICKS for incomplete timetables
 
	 */
 
	inline TimerGameTick::Ticks GetTimetableTotalDuration() const { return this->IsCompleteTimetable() ? this->timetable_duration : Ticks::INVALID_TICKS; }
 

	
 
	/**
 
	 * Gets the known duration of the vehicles timetable even if the timetable is not complete.
 
	 * @return known timetable duration
 
	 */
 
	inline TimerGameTick::Ticks GetTimetableDurationIncomplete() const { return this->timetable_duration; }
 

	
 
	/**
 
	 * Gets the known duration of the vehicles orders, timetabled or not.
 
	 * @return  known order duration.
 
	 */
 
	inline TimerGameTick::Ticks GetTotalDuration() const { return this->total_duration; }
 

	
 
	/**
 
	 * Must be called if an order's timetable is changed to update internal book keeping.
 
	 * @param delta By how many ticks has the timetable duration changed
 
	 */
 
	void UpdateTimetableDuration(TimerGameTick::Ticks delta) { this->timetable_duration += delta; }
 

	
 
	/**
 
	 * Must be called if an order's timetable is changed to update internal book keeping.
 
	 * @param delta By how many ticks has the total duration changed
src/order_cmd.cpp
Show inline comments
 
@@ -1926,52 +1926,52 @@ template <typename T, std::enable_if_t<s
 
static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value)
 
{
 
	return OrderConditionCompare(occ, static_cast<typename T::BaseType>(variable), value);
 
}
 

	
 
/**
 
 * Process a conditional order and determine the next order.
 
 * @param order the order the vehicle currently has
 
 * @param v the vehicle to update
 
 * @return index of next order to jump to, or INVALID_VEH_ORDER_ID to use the next order
 
 */
 
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
 
{
 
	if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
 

	
 
	bool skip_order = false;
 
	OrderConditionComparator occ = order->GetConditionComparator();
 
	uint16_t value = order->GetConditionValue();
 

	
 
	switch (order->GetConditionVariable()) {
 
		case OCV_LOAD_PERCENTAGE:    skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
 
		case OCV_RELIABILITY:        skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability),       value); break;
 
		case OCV_MAX_RELIABILITY:    skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability),   value); break;
 
		case OCV_MAX_SPEED:          skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
 
		case OCV_AGE:                skip_order = OrderConditionCompare(occ, DateToYear(v->age),                value); break;
 
		case OCV_AGE:                skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age),                value); break;
 
		case OCV_REQUIRES_SERVICE:   skip_order = OrderConditionCompare(occ, v->NeedsServicing(),               value); break;
 
		case OCV_UNCONDITIONALLY:    skip_order = true; break;
 
		case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, std::max(DateToYear(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1), TimerGameCalendar::Year(0)), value); break;
 
		case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, std::max(TimerGameCalendar::DateToYear(v->max_age - v->age + CalendarTime::DAYS_IN_LEAP_YEAR - 1), TimerGameCalendar::Year(0)), value); break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
 
}
 

	
 
/**
 
 * Update the vehicle's destination tile from an order.
 
 * @param order the order the vehicle currently has
 
 * @param v the vehicle to update
 
 * @param conditional_depth the depth (amount of steps) to go with conditional orders. This to prevent infinite loops.
 
 * @param pbs_look_ahead Whether we are forecasting orders for pbs reservations in advance. If true, the order indices must not be modified.
 
 */
 
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
 
{
 
	if (conditional_depth > v->GetNumOrders()) {
 
		v->current_order.Free();
 
		v->SetDestTile(0);
 
		return false;
 
	}
 

	
 
	switch (order->GetType()) {
 
		case OT_GOTO_STATION:
 
			v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
src/rail.cpp
Show inline comments
 
@@ -204,122 +204,122 @@ bool HasAnyRailtypesAvail(const CompanyI
 
 * @return true if the current company may build the rail.
 
 */
 
bool ValParamRailtype(const RailType rail)
 
{
 
	return rail < RAILTYPE_END && HasRailtypeAvail(_current_company, rail);
 
}
 

	
 
/**
 
 * Add the rail types that are to be introduced at the given date.
 
 * @param current The currently available railtypes.
 
 * @param date    The date for the introduction comparisons.
 
 * @return The rail types that should be available when date
 
 *         introduced rail types are taken into account as well.
 
 */
 
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
 
{
 
	RailTypes rts = current;
 

	
 
	for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
 
		const RailtypeInfo *rti = GetRailTypeInfo(rt);
 
		/* Unused rail type. */
 
		if (rti->label == 0) continue;
 

	
 
		/* Not date introduced. */
 
		if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE))) continue;
 
		if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(CalendarTime::MAX_DATE))) continue;
 

	
 
		/* Not yet introduced at this date. */
 
		if (rti->introduction_date > date) continue;
 

	
 
		/* Have we introduced all required railtypes? */
 
		RailTypes required = rti->introduction_required_railtypes;
 
		if ((rts & required) != required) continue;
 

	
 
		rts |= rti->introduces_railtypes;
 
	}
 

	
 
	/* When we added railtypes we need to run this method again; the added
 
	 * railtypes might enable more rail types to become introduced. */
 
	return rts == current ? rts : AddDateIntroducedRailTypes(rts, date);
 
}
 

	
 
/**
 
 * Get the rail types the given company can build.
 
 * @param company the company to get the rail types for.
 
 * @param introduces If true, include rail types introduced by other rail types
 
 * @return the rail types.
 
 */
 
RailTypes GetCompanyRailtypes(CompanyID company, bool introduces)
 
{
 
	RailTypes rts = RAILTYPES_NONE;
 

	
 
	for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
 
		const EngineInfo *ei = &e->info;
 

	
 
		if (HasBit(ei->climates, _settings_game.game_creation.landscape) &&
 
				(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + DAYS_IN_YEAR)) {
 
				(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
 
			const RailVehicleInfo *rvi = &e->u.rail;
 

	
 
			if (rvi->railveh_type != RAILVEH_WAGON) {
 
				assert(rvi->railtype < RAILTYPE_END);
 
				if (introduces) {
 
					rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes;
 
				} else {
 
					SetBit(rts, rvi->railtype);
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (introduces) return AddDateIntroducedRailTypes(rts, TimerGameCalendar::date);
 
	return rts;
 
}
 

	
 
/**
 
 * Get list of rail types, regardless of company availability.
 
 * @param introduces If true, include rail types introduced by other rail types
 
 * @return the rail types.
 
 */
 
RailTypes GetRailTypes(bool introduces)
 
{
 
	RailTypes rts = RAILTYPES_NONE;
 

	
 
	for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
 
		const EngineInfo *ei = &e->info;
 
		if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
 

	
 
		const RailVehicleInfo *rvi = &e->u.rail;
 
		if (rvi->railveh_type != RAILVEH_WAGON) {
 
			assert(rvi->railtype < RAILTYPE_END);
 
			if (introduces) {
 
				rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes;
 
			} else {
 
				SetBit(rts, rvi->railtype);
 
			}
 
		}
 
	}
 

	
 
	if (introduces) return AddDateIntroducedRailTypes(rts, MAX_DATE);
 
	if (introduces) return AddDateIntroducedRailTypes(rts, CalendarTime::MAX_DATE);
 
	return rts;
 
}
 

	
 
/**
 
 * Get the rail type for a given label.
 
 * @param label the railtype label.
 
 * @param allow_alternate_labels Search in the alternate label lists as well.
 
 * @return the railtype.
 
 */
 
RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels)
 
{
 
	/* Loop through each rail type until the label is found */
 
	for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
 
		const RailtypeInfo *rti = GetRailTypeInfo(r);
 
		if (rti->label == label) return r;
 
	}
 

	
 
	if (allow_alternate_labels) {
 
		/* Test if any rail type defines the label as an alternate. */
 
		for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) {
 
			const RailtypeInfo *rti = GetRailTypeInfo(r);
 
			if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r;
 
		}
 
	}
src/road.cpp
Show inline comments
 
@@ -94,49 +94,49 @@ RoadBits CleanUpRoadBits(const TileIndex
 
				}
 
			}
 

	
 
			/* If the neighbor tile is inconnective, remove the planned road connection to it */
 
			if (!connective) org_rb ^= target_rb;
 
		}
 
	}
 

	
 
	return org_rb;
 
}
 

	
 
/**
 
 * Finds out, whether given company has a given RoadType available for construction.
 
 * @param company ID of company
 
 * @param roadtypet RoadType to test
 
 * @return true if company has the requested RoadType available
 
 */
 
bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype)
 
{
 
	if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) {
 
		const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
 
		if (rti->label == 0) return false;
 

	
 
		/* Not yet introduced at this date. */
 
		if (IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) return false;
 
		if (IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(CalendarTime::MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) return false;
 

	
 
		/*
 
		 * Do not allow building hidden road types, except when a town may build it.
 
		 * The GS under deity mode, as well as anybody in the editor builds roads that are
 
		 * owned by towns. So if a town may build it, it should be buildable by them too.
 
		 */
 
		return (rti->flags & ROTFB_HIDDEN) == 0 || (rti->flags & ROTFB_TOWN_BUILD) != 0;
 
	} else {
 
		const Company *c = Company::GetIfValid(company);
 
		if (c == nullptr) return false;
 
		return HasBit(c->avail_roadtypes & ~_roadtypes_hidden_mask, roadtype);
 
	}
 
}
 

	
 
static RoadTypes GetMaskForRoadTramType(RoadTramType rtt)
 
{
 
	return rtt == RTT_TRAM ? _roadtypes_type : ~_roadtypes_type;
 
}
 

	
 
/**
 
 * Test if any buildable RoadType is available for a company.
 
 * @param company the company in question
 
 * @return true if company has any RoadTypes available
 
 */
 
@@ -152,117 +152,117 @@ bool HasAnyRoadTypesAvail(CompanyID comp
 
 */
 
bool ValParamRoadType(RoadType roadtype)
 
{
 
	return roadtype < ROADTYPE_END && HasRoadTypeAvail(_current_company, roadtype);
 
}
 

	
 
/**
 
 * Add the road types that are to be introduced at the given date.
 
 * @param rt      Roadtype
 
 * @param current The currently available roadtypes.
 
 * @param date    The date for the introduction comparisons.
 
 * @return The road types that should be available when date
 
 *         introduced road types are taken into account as well.
 
 */
 
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
 
{
 
	RoadTypes rts = current;
 

	
 
	for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
 
		const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
 
		/* Unused road type. */
 
		if (rti->label == 0) continue;
 

	
 
		/* Not date introduced. */
 
		if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(MAX_DATE))) continue;
 
		if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(CalendarTime::MAX_DATE))) continue;
 

	
 
		/* Not yet introduced at this date. */
 
		if (rti->introduction_date > date) continue;
 

	
 
		/* Have we introduced all required roadtypes? */
 
		RoadTypes required = rti->introduction_required_roadtypes;
 
		if ((rts & required) != required) continue;
 

	
 
		rts |= rti->introduces_roadtypes;
 
	}
 

	
 
	/* When we added roadtypes we need to run this method again; the added
 
	 * roadtypes might enable more rail types to become introduced. */
 
	return rts == current ? rts : AddDateIntroducedRoadTypes(rts, date);
 
}
 

	
 
/**
 
 * Get the road types the given company can build.
 
 * @param company the company to get the road types for.
 
 * @param introduces If true, include road types introduced by other road types
 
 * @return the road types.
 
 */
 
RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
 
{
 
	RoadTypes rts = ROADTYPES_NONE;
 

	
 
	for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
 
		const EngineInfo *ei = &e->info;
 

	
 
		if (HasBit(ei->climates, _settings_game.game_creation.landscape) &&
 
				(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + DAYS_IN_YEAR)) {
 
				(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
 
			const RoadVehicleInfo *rvi = &e->u.road;
 
			assert(rvi->roadtype < ROADTYPE_END);
 
			if (introduces) {
 
				rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
 
			} else {
 
				SetBit(rts, rvi->roadtype);
 
			}
 
		}
 
	}
 

	
 
	if (introduces) return AddDateIntroducedRoadTypes(rts, TimerGameCalendar::date);
 
	return rts;
 
}
 

	
 
/**
 
 * Get list of road types, regardless of company availability.
 
 * @param introduces If true, include road types introduced by other road types
 
 * @return the road types.
 
 */
 
RoadTypes GetRoadTypes(bool introduces)
 
{
 
	RoadTypes rts = ROADTYPES_NONE;
 

	
 
	for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
 
		const EngineInfo *ei = &e->info;
 
		if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
 

	
 
		const RoadVehicleInfo *rvi = &e->u.road;
 
		assert(rvi->roadtype < ROADTYPE_END);
 
		if (introduces) {
 
			rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
 
		} else {
 
			SetBit(rts, rvi->roadtype);
 
		}
 
	}
 

	
 
	if (introduces) return AddDateIntroducedRoadTypes(rts, MAX_DATE);
 
	if (introduces) return AddDateIntroducedRoadTypes(rts, CalendarTime::MAX_DATE);
 
	return rts;
 
}
 

	
 
/**
 
 * Get the road type for a given label.
 
 * @param label the roadtype label.
 
 * @param allow_alternate_labels Search in the alternate label lists as well.
 
 * @return the roadtype.
 
 */
 
RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
 
{
 
	/* Loop through each road type until the label is found */
 
	for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
 
		const RoadTypeInfo *rti = GetRoadTypeInfo(r);
 
		if (rti->label == label) return r;
 
	}
 

	
 
	if (allow_alternate_labels) {
 
		/* Test if any road type defines the label as an alternate. */
 
		for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
 
			const RoadTypeInfo *rti = GetRoadTypeInfo(r);
 
			if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r;
 
		}
 
	}
 
@@ -281,28 +281,28 @@ RoadType GetRoadTypeByLabel(RoadTypeLabe
 
 * @returns the existing RoadSubTypes
 
 */
 
RoadTypes ExistingRoadTypes(CompanyID c)
 
{
 
	/* Check only players which can actually own vehicles, editor and gamescripts are considered deities */
 
	if (c < OWNER_END) {
 
		const Company *company = Company::GetIfValid(c);
 
		if (company != nullptr) return company->avail_roadtypes;
 
	}
 

	
 
	RoadTypes known_roadtypes = ROADTYPES_NONE;
 

	
 
	/* Find used roadtypes */
 
	for (Engine *e : Engine::IterateType(VEH_ROAD)) {
 
		/* Check if the roadtype can be used in the current climate */
 
		if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
 

	
 
		/* Check whether available for all potential companies */
 
		if (e->company_avail != MAX_UVALUE(CompanyMask)) continue;
 

	
 
		known_roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes;
 
	}
 

	
 
	/* Get the date introduced roadtypes as well. */
 
	known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, MAX_DATE);
 
	known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, CalendarTime::MAX_DATE);
 

	
 
	return known_roadtypes;
 
}
src/road_cmd.cpp
Show inline comments
 
@@ -129,49 +129,49 @@ void InitRoadTypes()
 

	
 
	_sorted_roadtypes.clear();
 
	for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
 
		if (_roadtypes[rt].label != 0 && !HasBit(_roadtypes_hidden_mask, rt)) {
 
			_sorted_roadtypes.push_back(rt);
 
		}
 
	}
 
	std::sort(_sorted_roadtypes.begin(), _sorted_roadtypes.end(), CompareRoadTypes);
 
}
 

	
 
/**
 
 * Allocate a new road type label
 
 */
 
RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt)
 
{
 
	for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
 
		RoadTypeInfo *rti = &_roadtypes[rt];
 

	
 
		if (rti->label == 0) {
 
			/* Set up new road type */
 
			*rti = _original_roadtypes[(rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD];
 
			rti->label = label;
 
			rti->alternate_labels.clear();
 
			rti->flags = ROTFB_NONE;
 
			rti->introduction_date = INVALID_DATE;
 
			rti->introduction_date = CalendarTime::INVALID_DATE;
 

	
 
			/* Make us compatible with ourself. */
 
			rti->powered_roadtypes = (RoadTypes)(1ULL << rt);
 

	
 
			/* We also introduce ourself. */
 
			rti->introduces_roadtypes = (RoadTypes)(1ULL << rt);
 

	
 
			/* Default sort order; order of allocation, but with some
 
			 * offsets so it's easier for NewGRF to pick a spot without
 
			 * changing the order of other (original) road types.
 
			 * The << is so you can place other roadtypes in between the
 
			 * other roadtypes, the 7 is to be able to place something
 
			 * before the first (default) road type. */
 
			rti->sorting_order = rt << 2 | 7;
 

	
 
			/* Set bitmap of road/tram types */
 
			if (rtt == RTT_TRAM) {
 
				SetBit(_roadtypes_type, rt);
 
			} else {
 
				ClrBit(_roadtypes_type, rt);
 
			}
 

	
 
			return rt;
 
		}
src/roadveh_cmd.cpp
Show inline comments
 
@@ -1699,49 +1699,49 @@ static void CheckIfRoadVehNeedsService(R
 
		return;
 
	}
 

	
 
	SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
 
	v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
 
	v->SetDestTile(rfdd.tile);
 
	SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
 
}
 

	
 
void RoadVehicle::OnNewDay()
 
{
 
	AgeVehicle(this);
 

	
 
	if (!this->IsFrontEngine()) return;
 

	
 
	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
 
	if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
 

	
 
	CheckIfRoadVehNeedsService(this);
 

	
 
	CheckOrders(this);
 

	
 
	if (this->running_ticks == 0) return;
 

	
 
	CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * Ticks::DAY_TICKS));
 
	CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
 

	
 
	this->profit_this_year -= cost.GetCost();
 
	this->running_ticks = 0;
 

	
 
	SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
	SetWindowClassesDirty(WC_ROADVEH_LIST);
 
}
 

	
 
Trackdir RoadVehicle::GetVehicleTrackdir() const
 
{
 
	if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
 

	
 
	if (this->IsInDepot()) {
 
		/* We'll assume the road vehicle is facing outwards */
 
		return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
 
	}
 

	
 
	if (IsStandardRoadStopTile(this->tile)) {
 
		/* We'll assume the road vehicle is facing outwards */
 
		return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
 
	}
 

	
src/saveload/afterload.cpp
Show inline comments
 
@@ -238,49 +238,49 @@ void ClearAllCachedNames()
 
 * This is not done directly in AfterLoadGame because these
 
 * functions require that all saveload conversions have been
 
 * done. As people tend to add savegame conversion stuff after
 
 * the initialization of the windows and caches quite some bugs
 
 * had been made.
 
 * Moving this out of there is both cleaner and less bug-prone.
 
 */
 
static void InitializeWindowsAndCaches()
 
{
 
	/* Initialize windows */
 
	ResetWindowSystem();
 
	SetupColoursAndInitialWindow();
 

	
 
	/* Update coordinates of the signs. */
 
	ClearAllCachedNames();
 
	UpdateAllVirtCoords();
 
	ResetViewportAfterLoadGame();
 

	
 
	ScriptObject::InitializeRandomizers();
 

	
 
	for (Company *c : Company::Iterate()) {
 
		/* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it
 
		 * accordingly if it is not the case.  No need to set it on companies that are not been used already,
 
		 * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
 
		if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) {
 
		if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != CalendarTime::MIN_YEAR) {
 
			c->inaugurated_year = TimerGameCalendar::year;
 
		}
 
	}
 

	
 
	/* Count number of objects per type */
 
	for (Object *o : Object::Iterate()) {
 
		Object::IncTypeCount(o->type);
 
	}
 

	
 
	/* Identify owners of persistent storage arrays */
 
	for (Industry *i : Industry::Iterate()) {
 
		if (i->psa != nullptr) {
 
			i->psa->feature = GSF_INDUSTRIES;
 
			i->psa->tile = i->location.tile;
 
		}
 
	}
 
	for (Station *s : Station::Iterate()) {
 
		if (s->airport.psa != nullptr) {
 
			s->airport.psa->feature = GSF_AIRPORTS;
 
			s->airport.psa->tile = s->airport.tile;
 
		}
 
	}
 
	for (Town *t : Town::Iterate()) {
 
		for (auto &it : t->psa_list) {
 
@@ -755,55 +755,55 @@ bool AfterLoadGame()
 
	if (IsSavegameVersionBefore(SLV_133)) {
 
		_settings_game.vehicle.train_slope_steepness = 3;
 
	}
 
	if (IsSavegameVersionBefore(SLV_134))  _settings_game.economy.feeder_payment_share = 75;
 
	if (IsSavegameVersionBefore(SLV_138))  _settings_game.vehicle.plane_crashes = 2;
 
	if (IsSavegameVersionBefore(SLV_139)) {
 
		_settings_game.vehicle.roadveh_acceleration_model = 0;
 
		_settings_game.vehicle.roadveh_slope_steepness = 7;
 
	}
 
	if (IsSavegameVersionBefore(SLV_143))  _settings_game.economy.allow_town_level_crossings = true;
 
	if (IsSavegameVersionBefore(SLV_159)) {
 
		_settings_game.vehicle.max_train_length = 50;
 
		_settings_game.construction.max_bridge_length = 64;
 
		_settings_game.construction.max_tunnel_length = 64;
 
	}
 
	if (IsSavegameVersionBefore(SLV_166))  _settings_game.economy.infrastructure_maintenance = false;
 
	if (IsSavegameVersionBefore(SLV_183)) {
 
		_settings_game.linkgraph.distribution_pax = DT_MANUAL;
 
		_settings_game.linkgraph.distribution_mail = DT_MANUAL;
 
		_settings_game.linkgraph.distribution_armoured = DT_MANUAL;
 
		_settings_game.linkgraph.distribution_default = DT_MANUAL;
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_ENDING_YEAR)) {
 
		_settings_game.game_creation.ending_year = DEF_END_YEAR;
 
		_settings_game.game_creation.ending_year = CalendarTime::DEF_END_YEAR;
 
	}
 

	
 
	/* Convert linkgraph update settings from days to seconds. */
 
	if (IsSavegameVersionBefore(SLV_LINKGRAPH_SECONDS)) {
 
		_settings_game.linkgraph.recalc_interval *= SECONDS_PER_DAY;
 
		_settings_game.linkgraph.recalc_time     *= SECONDS_PER_DAY;
 
		_settings_game.linkgraph.recalc_interval *= CalendarTime::SECONDS_PER_DAY;
 
		_settings_game.linkgraph.recalc_time     *= CalendarTime::SECONDS_PER_DAY;
 
	}
 

	
 
	/* Load the sprites */
 
	GfxLoadSprites();
 
	LoadStringWidthTable();
 

	
 
	/* Copy temporary data to Engine pool */
 
	CopyTempEngineData();
 

	
 
	/* Connect front and rear engines of multiheaded trains and converts
 
	 * subtype to the new format */
 
	if (IsSavegameVersionBefore(SLV_17, 1)) ConvertOldMultiheadToNew();
 

	
 
	/* Connect front and rear engines of multiheaded trains */
 
	ConnectMultiheadedTrains();
 

	
 
	/* Fix the CargoPackets *and* fix the caches of CargoLists.
 
	 * If this isn't done before Stations and especially Vehicles are
 
	 * running their AfterLoad we might get in trouble. In the case of
 
	 * vehicles we could give the wrong (cached) count of items in a
 
	 * vehicle which causes different results when getting their caches
 
	 * filled; and that could eventually lead to desyncs. */
 
	CargoPacket::AfterLoad();
 

	
 
@@ -1401,60 +1401,60 @@ bool AfterLoadGame()
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_26)) {
 
		for (Station *st : Station::Iterate()) {
 
			st->last_vehicle_type = VEH_INVALID;
 
		}
 
	}
 

	
 
	YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
 

	
 
	if (IsSavegameVersionBefore(SLV_34)) {
 
		for (Company *c : Company::Iterate()) ResetCompanyLivery(c);
 
	}
 

	
 
	for (Company *c : Company::Iterate()) {
 
		c->avail_railtypes = GetCompanyRailtypes(c->index);
 
		c->avail_roadtypes = GetCompanyRoadTypes(c->index);
 
	}
 

	
 
	AfterLoadStations();
 

	
 
	/* Time starts at 0 instead of 1920.
 
	 * Account for this in older games by adding an offset */
 
	if (IsSavegameVersionBefore(SLV_31)) {
 
		TimerGameCalendar::date += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		TimerGameCalendar::year += ORIGINAL_BASE_YEAR;
 

	
 
		for (Station *st : Station::Iterate())   st->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Waypoint *wp : Waypoint::Iterate()) wp->build_date      += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Engine *e : Engine::Iterate())      e->intro_date       += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Company *c : Company::Iterate()) c->inaugurated_year += ORIGINAL_BASE_YEAR;
 
		for (Industry *i : Industry::Iterate())  i->last_prod_year   += ORIGINAL_BASE_YEAR;
 
		TimerGameCalendar::date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		TimerGameCalendar::year += CalendarTime::ORIGINAL_BASE_YEAR;
 

	
 
		for (Station *st : Station::Iterate())   st->build_date      += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Waypoint *wp : Waypoint::Iterate()) wp->build_date      += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Engine *e : Engine::Iterate())      e->intro_date       += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		for (Company *c : Company::Iterate()) c->inaugurated_year += CalendarTime::ORIGINAL_BASE_YEAR;
 
		for (Industry *i : Industry::Iterate())  i->last_prod_year   += CalendarTime::ORIGINAL_BASE_YEAR;
 

	
 
		for (Vehicle *v : Vehicle::Iterate()) {
 
			v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			v->build_year += ORIGINAL_BASE_YEAR;
 
			v->date_of_last_service += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			v->build_year += CalendarTime::ORIGINAL_BASE_YEAR;
 
		}
 
	}
 

	
 
	/* From 32 on we save the industry who made the farmland.
 
	 *  To give this prettiness to old savegames, we remove all farmfields and
 
	 *  plant new ones. */
 
	if (IsSavegameVersionBefore(SLV_32)) {
 
		for (auto t : Map::Iterate()) {
 
			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) {
 
				/* remove fields */
 
				MakeClear(t, CLEAR_GRASS, 3);
 
			}
 
		}
 

	
 
		for (Industry *i : Industry::Iterate()) {
 
			uint j;
 

	
 
			if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
 
				for (j = 0; j != 50; j++) PlantRandomFarmField(i);
 
			}
 
		}
 
	}
 

	
 
	/* Setting no refit flags to all orders in savegames from before refit in orders were added */
 
@@ -1904,49 +1904,49 @@ bool AfterLoadGame()
 
		for (RoadVehicle *v : RoadVehicle::Iterate()) {
 
			if (v->First() == v && HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) {
 
				ShowErrorMessage(STR_WARNING_LOADGAME_REMOVED_TRAMS, INVALID_STRING_ID, WL_CRITICAL);
 
				delete v;
 
			}
 
		}
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_99)) {
 
		for (auto t : Map::Iterate()) {
 
			/* Set newly introduced WaterClass of industry tiles */
 
			if (IsTileType(t, MP_STATION) && IsOilRig(t)) {
 
				SetWaterClassDependingOnSurroundings(t, true);
 
			}
 
			if (IsTileType(t, MP_INDUSTRY)) {
 
				if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) {
 
					SetWaterClassDependingOnSurroundings(t, true);
 
				} else {
 
					SetWaterClass(t, WATER_CLASS_INVALID);
 
				}
 
			}
 

	
 
			/* Replace "house construction year" with "house age" */
 
			if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) {
 
				t.m5() = ClampTo<uint8_t>(TimerGameCalendar::year - (t.m5() + ORIGINAL_BASE_YEAR));
 
				t.m5() = ClampTo<uint8_t>(TimerGameCalendar::year - (t.m5() + CalendarTime::ORIGINAL_BASE_YEAR));
 
			}
 
		}
 
	}
 

	
 
	/* Move the signal variant back up one bit for PBS. We don't convert the old PBS
 
	 * format here, as an old layout wouldn't work properly anyway. To be safe, we
 
	 * clear any possible PBS reservations as well. */
 
	if (IsSavegameVersionBefore(SLV_100)) {
 
		for (auto t : Map::Iterate()) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					if (HasSignals(t)) {
 
						/* move the signal variant */
 
						SetSignalVariant(t, TRACK_UPPER, HasBit(t.m2(), 2) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						SetSignalVariant(t, TRACK_LOWER, HasBit(t.m2(), 6) ? SIG_SEMAPHORE : SIG_ELECTRIC);
 
						ClrBit(t.m2(), 2);
 
						ClrBit(t.m2(), 6);
 
					}
 

	
 
					/* Clear PBS reservation on track */
 
					if (IsRailDepot(t)) {
 
						SetDepotReservation(t, false);
 
					} else {
 
						SetTrackReservation(t, TRACK_BIT_NONE);
src/saveload/misc_sl.cpp
Show inline comments
 
@@ -114,49 +114,49 @@ struct DATEChunkHandler : ChunkHandler {
 
		SlSetArrayIndex(0);
 
		SlGlobList(_date_desc);
 
	}
 

	
 
	void LoadCommon(const SaveLoadTable &slt, const SaveLoadCompatTable &slct) const
 
	{
 
		const std::vector<SaveLoad> oslt = SlCompatTableHeader(slt, slct);
 

	
 
		if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return;
 
		SlGlobList(oslt);
 
		if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many DATE entries");
 
	}
 

	
 
	void Load() const override
 
	{
 
		this->LoadCommon(_date_desc, _date_sl_compat);
 
	}
 

	
 

	
 
	void LoadCheck(size_t) const override
 
	{
 
		this->LoadCommon(_date_check_desc, _date_check_sl_compat);
 

	
 
		if (IsSavegameVersionBefore(SLV_31)) {
 
			_load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			_load_check_data.current_date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
		}
 
	}
 
};
 

	
 
static const SaveLoad _view_desc[] = {
 
	SLEG_CONDVAR("x",    _saved_scrollpos_x,    SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
 
	SLEG_CONDVAR("x",    _saved_scrollpos_x,    SLE_INT32,                  SLV_6, SL_MAX_VERSION),
 
	SLEG_CONDVAR("y",    _saved_scrollpos_y,    SLE_FILE_I16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_6),
 
	SLEG_CONDVAR("y",    _saved_scrollpos_y,    SLE_INT32,                  SLV_6, SL_MAX_VERSION),
 
	    SLEG_VAR("zoom", _saved_scrollpos_zoom, SLE_UINT8),
 
};
 

	
 
struct VIEWChunkHandler : ChunkHandler {
 
	VIEWChunkHandler() : ChunkHandler('VIEW', CH_TABLE) {}
 

	
 
	void Save() const override
 
	{
 
		SlTableHeader(_view_desc);
 

	
 
		SlSetArrayIndex(0);
 
		SlGlobList(_view_desc);
 
	}
 

	
 
	void Load() const override
src/saveload/oldloader_sl.cpp
Show inline comments
 
@@ -377,61 +377,61 @@ static bool FixTTOEngines()
 
	static const EngineID tto_to_ttd[] = {
 
		  0,   0,   8,   8,   8,   8,   8,   9,  10,  11,  12,  13,  14,  15,  15,  22,
 
		 23,  24,  25,  26,  27,  29,  28,  30,  31,  32,  33,  34,  35,  36,  37,  55,
 
		 57,  59,  58,  60,  61,  62,  63,  64,  65,  66,  67, 116, 116, 117, 118, 123,
 
		124, 126, 127, 132, 133, 135, 136, 138, 139, 141, 142, 144, 145, 147, 148, 150,
 
		151, 153, 154, 204, 205, 206, 207, 208, 211, 212, 211, 212, 211, 212, 215, 216,
 
		217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
 
		233, 234, 235, 236, 237, 238, 253
 
	};
 

	
 
	for (Vehicle *v : Vehicle::Iterate()) {
 
		if (v->engine_type >= lengthof(tto_to_ttd)) return false;
 
		v->engine_type = tto_to_ttd[v->engine_type];
 
	}
 

	
 
	/* Load the default engine set. Many of them will be overridden later */
 
	{
 
		uint j = 0;
 
		for (uint i = 0; i < lengthof(_orig_rail_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_TRAIN, i);
 
		for (uint i = 0; i < lengthof(_orig_road_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_ROAD, i);
 
		for (uint i = 0; i < lengthof(_orig_ship_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_SHIP, i);
 
		for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_AIRCRAFT, i);
 
	}
 

	
 
	TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date + DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::ConvertYMDToDate(2050, 0, 1));
 
	TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::ConvertYMDToDate(2050, 0, 1));
 

	
 
	for (EngineID i = 0; i < 256; i++) {
 
		int oi = ttd_to_tto[i];
 
		Engine *e = GetTempDataEngine(i);
 

	
 
		if (oi == 255) {
 
			/* Default engine is used */
 
			TimerGameCalendar::date += DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			TimerGameCalendar::date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			StartupOneEngine(e, aging_date, 0);
 
			CalcEngineReliability(e, false);
 
			e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			TimerGameCalendar::date -= DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			e->intro_date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			TimerGameCalendar::date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
 

	
 
			/* Make sure for example monorail and maglev are available when they should be */
 
			if (TimerGameCalendar::date >= e->intro_date && HasBit(e->info.climates, 0)) {
 
				e->flags |= ENGINE_AVAILABLE;
 
				e->company_avail = MAX_UVALUE(CompanyMask);
 
				e->age = TimerGameCalendar::date > e->intro_date ? static_cast<int32_t>(TimerGameCalendar::date - e->intro_date) / 30 : 0;
 
			}
 
		} else {
 
			/* Using data from TTO savegame */
 
			Engine *oe = &_old_engines[oi];
 

	
 
			e->intro_date          = oe->intro_date;
 
			e->age                 = oe->age;
 
			e->reliability         = oe->reliability;
 
			e->reliability_spd_dec = oe->reliability_spd_dec;
 
			e->reliability_start   = oe->reliability_start;
 
			e->reliability_max     = oe->reliability_max;
 
			e->reliability_final   = oe->reliability_final;
 
			e->duration_phase_1    = oe->duration_phase_1;
 
			e->duration_phase_2    = oe->duration_phase_2;
 
			e->duration_phase_3    = oe->duration_phase_3;
 
			e->flags               = oe->flags;
 

	
 
			e->company_avail = 0;
 
@@ -999,49 +999,49 @@ static bool LoadOldCompany(LoadgameState
 
	} else {
 
		c->name_1 = RemapOldStringID(_old_string_id);
 
		c->president_name_1 = RemapOldStringID(_old_string_id_2);
 

	
 
		if (num == 0) {
 
			/* If the first company has no name, make sure we call it UNNAMED */
 
			if (c->name_1 == 0) {
 
				c->name_1 = STR_SV_UNNAMED;
 
			}
 
		} else {
 
			/* Beside some multiplayer maps (1 on 1), which we don't official support,
 
			 * all other companies are an AI.. mark them as such */
 
			c->is_ai = true;
 
		}
 

	
 
		/* Sometimes it is better to not ask.. in old scenarios, the money
 
		 * was always 893288 pounds. In the newer versions this is correct,
 
		 * but correct for those oldies
 
		 * Ps: this also means that if you had exact 893288 pounds, you will go back
 
		 * to 100000.. this is a very VERY small chance ;) */
 
		if (c->money == 893288) c->money = c->current_loan = 100000;
 
	}
 

	
 
	_company_colours[num] = (Colours)c->colour;
 
	c->inaugurated_year -= ORIGINAL_BASE_YEAR;
 
	c->inaugurated_year -= CalendarTime::ORIGINAL_BASE_YEAR;
 

	
 
	return true;
 
}
 

	
 
static uint32_t _old_order_ptr;
 
static uint16_t _old_next_ptr;
 
static VehicleID _current_vehicle_id;
 

	
 
static const OldChunks vehicle_train_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, Train, track ),
 
	OCL_SVAR(  OC_UINT8, Train, force_proceed ),
 
	OCL_SVAR( OC_UINT16, Train, crash_anim_pos ),
 
	OCL_SVAR(  OC_UINT8, Train, railtype ),
 

	
 
	OCL_NULL( 5 ), ///< Junk
 

	
 
	OCL_END()
 
};
 

	
 
static const OldChunks vehicle_road_chunk[] = {
 
	OCL_SVAR(  OC_UINT8, RoadVehicle, state ),
 
	OCL_SVAR(  OC_UINT8, RoadVehicle, frame ),
 
	OCL_SVAR( OC_UINT16, RoadVehicle, blocked_ctr ),
 
	OCL_SVAR(  OC_UINT8, RoadVehicle, overtaking ),
src/script/api/script_date.cpp
Show inline comments
 
@@ -35,35 +35,35 @@
 
}
 

	
 
/* static */ SQInteger ScriptDate::GetMonth(ScriptDate::Date date)
 
{
 
	if (date < 0) return DATE_INVALID;
 

	
 
	::TimerGameCalendar::YearMonthDay ymd;
 
	::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 
	return ymd.month + 1;
 
}
 

	
 
/* static */ SQInteger ScriptDate::GetDayOfMonth(ScriptDate::Date date)
 
{
 
	if (date < 0) return DATE_INVALID;
 

	
 
	::TimerGameCalendar::YearMonthDay ymd;
 
	::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 
	return ymd.day;
 
}
 

	
 
/* static */ ScriptDate::Date ScriptDate::GetDate(SQInteger year, SQInteger month, SQInteger day_of_month)
 
{
 
	if (month < 1 || month > 12) return DATE_INVALID;
 
	if (day_of_month < 1 || day_of_month > 31) return DATE_INVALID;
 
	if (year < 0 || year > MAX_YEAR) return DATE_INVALID;
 
	if (year < 0 || year > CalendarTime::MAX_YEAR) return DATE_INVALID;
 

	
 
	return (ScriptDate::Date)(int32_t)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month);
 
}
 

	
 
/* static */ SQInteger ScriptDate::GetSystemTime()
 
{
 
	time_t t;
 
	time(&t);
 
	return t;
 
}
src/script/api/script_date.hpp
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * 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.
 
 * 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.
 
 * 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/>.
 
 */
 

	
 
/** @file script_date.hpp Everything to query and manipulate date related information. */
 

	
 
#ifndef SCRIPT_DATE_HPP
 
#define SCRIPT_DATE_HPP
 

	
 
#include "script_object.hpp"
 
#include "timer/timer_game_calendar.h"
 
#include "../../date_type.h"
 

	
 
/**
 
 * Class that handles all date related (calculation) functions.
 
 * @api ai game
 
 *
 
 * @note Months and days of month are 1-based; the first month of the
 
 *       year is 1 and the first day of the month is also 1.
 
 * @note Years are zero based; they start with the year 0.
 
 * @note Dates can be used to determine the number of days between
 
 *       two different moments in time because they count the number
 
 *       of days since the year 0.
 
 */
 
class ScriptDate : public ScriptObject {
 
public:
 
	/**
 
	 * Date data type is an integer value. Use ScriptDate::GetDate to
 
	 * compose valid date values for a known year, month and day.
 
	 */
 
	enum Date {
 
		DATE_INVALID = (int32_t)::INVALID_DATE, ///< A value representing an invalid date.
 
		DATE_INVALID = (int32_t)::CalendarTime::INVALID_DATE, ///< A value representing an invalid date.
 
	};
 

	
 
	/**
 
	 * Validates if a date value represent a valid date.
 
	 * @param date The date to validate.
 
	 * @return True if the date is valid, otherwise false
 
	 */
 
	static bool IsValidDate(Date date);
 

	
 
	/**
 
	 * Get the current date.
 
	 * This is the number of days since epoch under the assumption that
 
	 *  there is a leap year every 4 years, except when dividable by
 
	 *  100 but not by 400.
 
	 * @return The current date.
 
	 */
 
	static Date GetCurrentDate();
 

	
 
	/**
 
	 * Get the year of the given date.
 
	 * @param date The date to get the year of.
 
	 * @return The year.
 
	 */
 
	static SQInteger GetYear(Date date);
src/settings.cpp
Show inline comments
 
@@ -1262,50 +1262,50 @@ bool IsConversionNeeded(ConfigIniFile &i
 
/**
 
 * Load the values from the configuration files
 
 * @param startup Load the minimal amount of the configuration to "bootstrap" the blitter and such.
 
 */
 
void LoadFromConfig(bool startup)
 
{
 
	ConfigIniFile generic_ini(_config_file);
 
	ConfigIniFile private_ini(_private_file);
 
	ConfigIniFile secrets_ini(_secrets_file);
 

	
 
	if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
 

	
 
	IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
 

	
 
	/* Before the split of private/secrets, we have to look in the generic for these settings. */
 
	if (generic_version < IFV_PRIVATE_SECRETS) {
 
		HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
 
	} else {
 
		HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
 
	}
 

	
 
	/* Load basic settings only during bootstrap, load other settings not during bootstrap */
 
	if (!startup) {
 
		if (generic_version < IFV_LINKGRAPH_SECONDS) {
 
			_settings_newgame.linkgraph.recalc_interval *= SECONDS_PER_DAY;
 
			_settings_newgame.linkgraph.recalc_time     *= SECONDS_PER_DAY;
 
			_settings_newgame.linkgraph.recalc_interval *= CalendarTime::SECONDS_PER_DAY;
 
			_settings_newgame.linkgraph.recalc_time     *= CalendarTime::SECONDS_PER_DAY;
 
		}
 

	
 
		/* Move no_http_content_downloads and use_relay_service from generic_ini to private_ini. */
 
		if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
 
			IniGroup *network = generic_ini.GetGroup("network", false);
 
			if (network != nullptr) {
 
				IniItem *no_http_content_downloads = network->GetItem("no_http_content_downloads");
 
				if (no_http_content_downloads != nullptr) {
 
					if (no_http_content_downloads->value == "true") {
 
						_settings_client.network.no_http_content_downloads = true;
 
					} else if (no_http_content_downloads->value == "false") {
 
						_settings_client.network.no_http_content_downloads = false;
 
					}
 
				}
 

	
 
				IniItem *use_relay_service = network->GetItem("use_relay_service");
 
				if (use_relay_service != nullptr) {
 
					if (use_relay_service->value == "never") {
 
						_settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
 
					} else if (use_relay_service->value == "ask") {
 
						_settings_client.network.use_relay_service = UseRelayService::URS_ASK;
 
					} else if (use_relay_service->value == "allow") {
 
						_settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
 
					}
src/settings_gui.cpp
Show inline comments
 
@@ -2730,49 +2730,49 @@ void DrawDropDownButton(int x, int y, Co
 
 */
 
void DrawBoolButton(int x, int y, bool state, bool clickable)
 
{
 
	static const Colours _bool_ctabs[2][2] = {{COLOUR_CREAM, COLOUR_RED}, {COLOUR_DARK_GREEN, COLOUR_GREEN}};
 

	
 
	Rect r = {x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1};
 
	DrawFrameRect(r, _bool_ctabs[state][clickable], state ? FR_LOWERED : FR_NONE);
 
}
 

	
 
struct CustomCurrencyWindow : Window {
 
	int query_widget;
 

	
 
	CustomCurrencyWindow(WindowDesc *desc) : Window(desc)
 
	{
 
		this->InitNested();
 

	
 
		SetButtonState();
 
	}
 

	
 
	void SetButtonState()
 
	{
 
		this->SetWidgetDisabledState(WID_CC_RATE_DOWN, _custom_currency.rate == 1);
 
		this->SetWidgetDisabledState(WID_CC_RATE_UP, _custom_currency.rate == UINT16_MAX);
 
		this->SetWidgetDisabledState(WID_CC_YEAR_DOWN, _custom_currency.to_euro == CF_NOEURO);
 
		this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == MAX_YEAR);
 
		this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == CalendarTime::MAX_YEAR);
 
	}
 

	
 
	void SetStringParameters(int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_CC_RATE:      SetDParam(0, 1); SetDParam(1, 1);            break;
 
			case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); break;
 
			case WID_CC_PREFIX:    SetDParamStr(0, _custom_currency.prefix);    break;
 
			case WID_CC_SUFFIX:    SetDParamStr(0, _custom_currency.suffix);    break;
 
			case WID_CC_YEAR:
 
				SetDParam(0, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER);
 
				SetDParam(1, _custom_currency.to_euro);
 
				break;
 

	
 
			case WID_CC_PREVIEW:
 
				SetDParam(0, 10000);
 
				break;
 
		}
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		switch (widget) {
 
			/* Set the appropriate width for the edit 'buttons' */
 
@@ -2829,96 +2829,96 @@ struct CustomCurrencyWindow : Window {
 

	
 
			case WID_CC_PREFIX_EDIT:
 
			case WID_CC_PREFIX:
 
				SetDParamStr(0, _custom_currency.prefix);
 
				str = STR_JUST_RAW_STRING;
 
				len = 15;
 
				line = WID_CC_PREFIX;
 
				break;
 

	
 
			case WID_CC_SUFFIX_EDIT:
 
			case WID_CC_SUFFIX:
 
				SetDParamStr(0, _custom_currency.suffix);
 
				str = STR_JUST_RAW_STRING;
 
				len = 15;
 
				line = WID_CC_SUFFIX;
 
				break;
 

	
 
			case WID_CC_YEAR_DOWN:
 
				_custom_currency.to_euro = (_custom_currency.to_euro <= MIN_EURO_YEAR) ? CF_NOEURO : _custom_currency.to_euro - 1;
 
				if (_custom_currency.to_euro == CF_NOEURO) this->DisableWidget(WID_CC_YEAR_DOWN);
 
				this->EnableWidget(WID_CC_YEAR_UP);
 
				break;
 

	
 
			case WID_CC_YEAR_UP:
 
				_custom_currency.to_euro = Clamp(_custom_currency.to_euro + 1, MIN_EURO_YEAR, MAX_YEAR);
 
				if (_custom_currency.to_euro == MAX_YEAR) this->DisableWidget(WID_CC_YEAR_UP);
 
				_custom_currency.to_euro = Clamp(_custom_currency.to_euro + 1, MIN_EURO_YEAR, CalendarTime::MAX_YEAR);
 
				if (_custom_currency.to_euro == CalendarTime::MAX_YEAR) this->DisableWidget(WID_CC_YEAR_UP);
 
				this->EnableWidget(WID_CC_YEAR_DOWN);
 
				break;
 

	
 
			case WID_CC_YEAR:
 
				SetDParam(0, _custom_currency.to_euro);
 
				str = STR_JUST_INT;
 
				len = 7;
 
				line = WID_CC_YEAR;
 
				afilter = CS_NUMERAL;
 
				break;
 
		}
 

	
 
		if (len != 0) {
 
			this->query_widget = line;
 
			ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, this, afilter, QSF_NONE);
 
		}
 

	
 
		this->SetTimeout();
 
		this->SetDirty();
 
	}
 

	
 
	void OnQueryTextFinished(char *str) override
 
	{
 
		if (str == nullptr) return;
 

	
 
		switch (this->query_widget) {
 
			case WID_CC_RATE:
 
				_custom_currency.rate = Clamp(atoi(str), 1, UINT16_MAX);
 
				break;
 

	
 
			case WID_CC_SEPARATOR: // Thousands separator
 
				_custom_currency.separator = str;
 
				break;
 

	
 
			case WID_CC_PREFIX:
 
				_custom_currency.prefix = str;
 
				break;
 

	
 
			case WID_CC_SUFFIX:
 
				_custom_currency.suffix = str;
 
				break;
 

	
 
			case WID_CC_YEAR: { // Year to switch to euro
 
				TimerGameCalendar::Year val = atoi(str);
 

	
 
				_custom_currency.to_euro = (val < MIN_EURO_YEAR ? CF_NOEURO : std::min(val, MAX_YEAR));
 
				_custom_currency.to_euro = (val < MIN_EURO_YEAR ? CF_NOEURO : std::min(val, CalendarTime::MAX_YEAR));
 
				break;
 
			}
 
		}
 
		MarkWholeScreenDirty();
 
		SetButtonState();
 
	}
 

	
 
	void OnTimeout() override
 
	{
 
		this->SetDirty();
 
	}
 
};
 

	
 
static const NWidgetPart _nested_cust_currency_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
 
		NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CURRENCY_WINDOW, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_GREY),
 
		NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(7, 3, 0),
 
			NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5),
 
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP),
 
				NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP),
 
				NWidget(NWID_SPACER), SetMinimalSize(5, 0),
src/ship_cmd.cpp
Show inline comments
 
@@ -215,49 +215,49 @@ void Ship::UpdateCache()
 
	this->UpdateVisualEffect();
 
}
 

	
 
Money Ship::GetRunningCost() const
 
{
 
	const Engine *e = this->GetEngine();
 
	uint cost_factor = GetVehicleProperty(this, PROP_SHIP_RUNNING_COST_FACTOR, e->u.ship.running_cost);
 
	return GetPrice(PR_RUNNING_SHIP, cost_factor, e->GetGRF());
 
}
 

	
 
void Ship::OnNewDay()
 
{
 
	if ((++this->day_counter & 7) == 0) {
 
		DecreaseVehicleValue(this);
 
	}
 

	
 
	CheckVehicleBreakdown(this);
 
	AgeVehicle(this);
 
	CheckIfShipNeedsService(this);
 

	
 
	CheckOrders(this);
 

	
 
	if (this->running_ticks == 0) return;
 

	
 
	CommandCost cost(EXPENSES_SHIP_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * Ticks::DAY_TICKS));
 
	CommandCost cost(EXPENSES_SHIP_RUN, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
 

	
 
	this->profit_this_year -= cost.GetCost();
 
	this->running_ticks = 0;
 

	
 
	SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
	/* we need this for the profit */
 
	SetWindowClassesDirty(WC_SHIPS_LIST);
 
}
 

	
 
Trackdir Ship::GetVehicleTrackdir() const
 
{
 
	if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
 

	
 
	if (this->IsInDepot()) {
 
		/* We'll assume the ship is facing outwards */
 
		return DiagDirToDiagTrackdir(GetShipDepotDirection(this->tile));
 
	}
 

	
 
	if (this->state == TRACK_BIT_WORMHOLE) {
 
		/* ship on aqueduct, so just use its direction and assume a diagonal track */
 
		return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
 
	}
src/station.cpp
Show inline comments
 
@@ -84,49 +84,49 @@ Station::~Station()
 
{
 
	if (CleaningPool()) {
 
		for (CargoID c = 0; c < NUM_CARGO; c++) {
 
			this->goods[c].cargo.OnCleanPool();
 
		}
 
		return;
 
	}
 

	
 
	while (!this->loading_vehicles.empty()) {
 
		this->loading_vehicles.front()->LeaveStation();
 
	}
 

	
 
	for (Aircraft *a : Aircraft::Iterate()) {
 
		if (!a->IsNormalAircraft()) continue;
 
		if (a->targetairport == this->index) a->targetairport = INVALID_STATION;
 
	}
 

	
 
	for (CargoID c = 0; c < NUM_CARGO; ++c) {
 
		LinkGraph *lg = LinkGraph::GetIfValid(this->goods[c].link_graph);
 
		if (lg == nullptr) continue;
 

	
 
		for (NodeID node = 0; node < lg->Size(); ++node) {
 
			Station *st = Station::Get((*lg)[node].station);
 
			st->goods[c].flows.erase(this->index);
 
			if ((*lg)[node].HasEdgeTo(this->goods[c].node) && (*lg)[node][this->goods[c].node].LastUpdate() != INVALID_DATE) {
 
			if ((*lg)[node].HasEdgeTo(this->goods[c].node) && (*lg)[node][this->goods[c].node].LastUpdate() != CalendarTime::INVALID_DATE) {
 
				st->goods[c].flows.DeleteFlows(this->index);
 
				RerouteCargo(st, c, this->index, st->index);
 
			}
 
		}
 
		lg->RemoveNode(this->goods[c].node);
 
		if (lg->Size() == 0) {
 
			LinkGraphSchedule::instance.Unqueue(lg);
 
			delete lg;
 
		}
 
	}
 

	
 
	for (Vehicle *v : Vehicle::Iterate()) {
 
		/* Forget about this station if this station is removed */
 
		if (v->last_station_visited == this->index) {
 
			v->last_station_visited = INVALID_STATION;
 
		}
 
		if (v->last_loading_station == this->index) {
 
			v->last_loading_station = INVALID_STATION;
 
		}
 
	}
 

	
 
	/* Remove station from industries and towns that reference it. */
 
	this->RemoveFromAllNearbyLists();
 

	
src/station_cmd.cpp
Show inline comments
 
@@ -3842,53 +3842,53 @@ void DeleteStaleLinks(Station *from)
 
						}
 
						if (edge.LastUpdate() == TimerGameCalendar::date) {
 
							updated = true;
 
							break;
 
						}
 

	
 
						Vehicle *next_shared = v->NextShared();
 
						if (next_shared) {
 
							*iter = next_shared;
 
							++iter;
 
						} else {
 
							iter = vehicles.erase(iter);
 
						}
 

	
 
						if (iter == vehicles.end()) iter = vehicles.begin();
 
					}
 
				}
 

	
 
				if (!updated) {
 
					/* If it's still considered dead remove it. */
 
					to_remove.emplace_back(to->goods[c].node);
 
					ge.flows.DeleteFlows(to->index);
 
					RerouteCargo(from, c, to->index, from->index);
 
				}
 
			} else if (edge.last_unrestricted_update != INVALID_DATE && TimerGameCalendar::date - edge.last_unrestricted_update > timeout) {
 
			} else if (edge.last_unrestricted_update != CalendarTime::INVALID_DATE && TimerGameCalendar::date - edge.last_unrestricted_update > timeout) {
 
				edge.Restrict();
 
				ge.flows.RestrictFlows(to->index);
 
				RerouteCargo(from, c, to->index, from->index);
 
			} else if (edge.last_restricted_update != INVALID_DATE && TimerGameCalendar::date - edge.last_restricted_update > timeout) {
 
			} else if (edge.last_restricted_update != CalendarTime::INVALID_DATE && TimerGameCalendar::date - edge.last_restricted_update > timeout) {
 
				edge.Release();
 
			}
 
		}
 
		/* Remove dead edges. */
 
		for (NodeID r : to_remove) (*lg)[ge.node].RemoveEdge(r);
 

	
 
		assert(TimerGameCalendar::date >= lg->LastCompression());
 
		if (TimerGameCalendar::date - lg->LastCompression() > LinkGraph::COMPRESSION_INTERVAL) {
 
			lg->Compress();
 
		}
 
	}
 
}
 

	
 
/**
 
 * Increase capacity for a link stat given by station cargo and next hop.
 
 * @param st Station to get the link stats from.
 
 * @param cargo Cargo to increase stat for.
 
 * @param next_station_id Station the consist will be travelling to next.
 
 * @param capacity Capacity to add to link stat.
 
 * @param usage Usage to add to link stat.
 
 * @param mode Update mode to be applied.
 
 */
 
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode)
 
{
src/statusbar_gui.cpp
Show inline comments
 
@@ -68,49 +68,49 @@ struct StatusBarWindow : Window {
 
	{
 
		this->ticker_scroll = TICKER_STOP;
 

	
 
		this->InitNested();
 
		CLRBITS(this->flags, WF_WHITE_BORDER);
 
		PositionStatusbar(this);
 
	}
 

	
 
	Point OnInitialPosition(int16_t sm_width, int16_t sm_height, int window_number) override
 
	{
 
		Point pt = { 0, _screen.height - sm_height };
 
		return pt;
 
	}
 

	
 
	void FindWindowPlacementAndResize(int def_width, int def_height) override
 
	{
 
		Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
 
	}
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		Dimension d;
 
		switch (widget) {
 
			case WID_S_LEFT:
 
				SetDParamMaxValue(0, DateAtStartOfYear(MAX_YEAR));
 
				SetDParamMaxValue(0, TimerGameCalendar::DateAtStartOfYear(CalendarTime::MAX_YEAR));
 
				d = GetStringBoundingBox(STR_JUST_DATE_LONG);
 
				break;
 

	
 
			case WID_S_RIGHT: {
 
				int64_t max_money = UINT32_MAX;
 
				for (const Company *c : Company::Iterate()) max_money = std::max<int64_t>(c->money, max_money);
 
				SetDParam(0, 100LL * max_money);
 
				d = GetStringBoundingBox(STR_JUST_CURRENCY_LONG);
 
				break;
 
			}
 

	
 
			default:
 
				return;
 
		}
 

	
 
		d.width += padding.width;
 
		d.height += padding.height;
 
		*size = maxdim(d, *size);
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		Rect tr = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
 
		tr.top = CenterBounds(r.top, r.bottom, FONT_HEIGHT_NORMAL);
src/story_gui.cpp
Show inline comments
 
@@ -678,49 +678,49 @@ public:
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		if (widget != WID_SB_PAGE_PANEL) return;
 

	
 
		StoryPage *page = this->GetSelPage();
 
		if (page == nullptr) return;
 

	
 
		Rect fr = r.Shrink(WidgetDimensions::scaled.frametext);
 

	
 
		/* Set up a clipping region for the panel. */
 
		DrawPixelInfo tmp_dpi;
 
		if (!FillDrawPixelInfo(&tmp_dpi, fr.left, fr.top, fr.Width(), fr.Height())) return;
 

	
 
		AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
 

	
 
		/* Draw content (now coordinates given to Draw** are local to the new clipping region). */
 
		fr = fr.Translate(-fr.left, -fr.top);
 
		int line_height = FONT_HEIGHT_NORMAL;
 
		const int scrollpos = this->vscroll->GetPosition();
 
		int y_offset = -scrollpos;
 

	
 
		/* Date */
 
		if (page->date != INVALID_DATE) {
 
		if (page->date != CalendarTime::INVALID_DATE) {
 
			SetDParam(0, page->date);
 
			DrawString(0, fr.right, y_offset, STR_JUST_DATE_LONG, TC_BLACK);
 
		}
 
		y_offset += line_height;
 

	
 
		/* Title */
 
		SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
 
		y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER);
 

	
 
		/* Page elements */
 
		this->EnsureStoryPageElementLayout();
 
		for (const LayoutCacheElement &ce : this->layout_cache) {
 
			y_offset = ce.bounds.top - scrollpos;
 
			switch (ce.pe->type) {
 
				case SPET_TEXT:
 
					SetDParamStr(0, ce.pe->text);
 
					y_offset = DrawStringMultiLine(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_LEFT);
 
					break;
 

	
 
				case SPET_GOAL: {
 
					Goal *g = Goal::Get((GoalID) ce.pe->referenced_id);
 
					StringID string_id = g == nullptr ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING;
 
					if (g != nullptr) SetDParamStr(0, g->text);
 
					DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe), string_id);
src/subsidy.cpp
Show inline comments
 
@@ -24,49 +24,49 @@
 
#include "game/game.hpp"
 
#include "command_func.h"
 
#include "string_func.h"
 
#include "tile_cmd.h"
 
#include "subsidy_cmd.h"
 
#include "timer/timer.h"
 
#include "timer/timer_game_calendar.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "safeguards.h"
 

	
 
SubsidyPool _subsidy_pool("Subsidy"); ///< Pool for the subsidies.
 
INSTANTIATE_POOL_METHODS(Subsidy)
 

	
 
/**
 
 * Marks subsidy as awarded, creates news and AI event
 
 * @param company awarded company
 
 */
 
void Subsidy::AwardTo(CompanyID company)
 
{
 
	assert(!this->IsAwarded());
 

	
 
	this->awarded = company;
 
	this->remaining = _settings_game.difficulty.subsidy_duration * MONTHS_IN_YEAR;
 
	this->remaining = _settings_game.difficulty.subsidy_duration * CalendarTime::MONTHS_IN_YEAR;
 

	
 
	SetDParam(0, company);
 
	NewsStringData *company_name = new NewsStringData(GetString(STR_COMPANY_NAME));
 

	
 
	/* Add a news item */
 
	std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(this, SubsidyDecodeParamType::NewsAwarded, 1);
 

	
 
	SetDParamStr(0, company_name->string);
 
	AddNewsItem(
 
		STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
 
		NT_SUBSIDIES, NF_NORMAL,
 
		reftype.first, this->src, reftype.second, this->dst,
 
		company_name
 
	);
 
	AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index));
 
	Game::NewEvent(new ScriptEventSubsidyAwarded(this->index));
 

	
 
	InvalidateWindowData(WC_SUBSIDIES_LIST, 0);
 
}
 

	
 
/**
 
 * Setup the string parameters for printing the subsidy at the screen, and compute the news reference for the subsidy.
 
 * @param s %Subsidy being printed.
 
 * @param mode Type of subsidy news message to decide on parameter format.
src/table/airport_defaults.h
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * 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.
 
 * 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.
 
 * 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/>.
 
 */
 

	
 
/** @file airport_defaults.h Tables with default values for airports and airport tiles. */
 

	
 
#ifndef AIRPORT_DEFAULTS_H
 
#define AIRPORT_DEFAULTS_H
 

	
 
#include "date_type.h"
 
#include "timer/timer_game_calendar.h"
 

	
 
/**
 
 * Definition of an airport tiles layout.
 
 * @param x offset x of this tile
 
 * @param y offset y of this tile
 
 * @param m StationGfx of the tile
 
 * @see _airport_specs
 
 * @see AirportTileTable
 
 */
 
#define MK(x, y, m) {{x, y}, m}
 

	
 
/**
 
 * Terminator of airport tiles layout definition
 
 */
 
#define MKEND {{-0x80, 0}, 0}
 

	
 
/** Tiles for Country Airfield (small) */
 
static const AirportTileTable _tile_table_country_0[] = {
 
	MK(0, 0, APT_SMALL_BUILDING_1),
 
	MK(1, 0, APT_SMALL_BUILDING_2),
 
	MK(2, 0, APT_SMALL_BUILDING_3),
 
	MK(3, 0, APT_SMALL_DEPOT_SE),
 
	MK(0, 1, APT_GRASS_FENCE_NE_FLAG),
 
	MK(1, 1, APT_GRASS_1),
 
@@ -376,44 +376,44 @@ static const AirportTileTable * const _t
 
static const Direction _default_airports_rotation[] = {
 
	DIR_N,
 
};
 

	
 
#undef MK
 
#undef MKEND
 

	
 
/** General AirportSpec definition. */
 
#define AS_GENERIC(fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, enabled) \
 
	{fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, preview, maint_cost, enabled, GRFFileProps(AT_INVALID)}
 

	
 
/** AirportSpec definition for airports without any depot. */
 
#define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \
 
	AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), nullptr, 0, \
 
		size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true)
 

	
 
/** AirportSpec definition for airports with at least one depot. */
 
#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \
 
	AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), _airport_depots_##ap_name, lengthof(_airport_depots_##ap_name), \
 
		size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true)
 

	
 
/* The helidepot and helistation have ATP_TTDP_SMALL because they are at ground level */
 
extern const AirportSpec _origin_airport_specs[] = {
 
	AS(country,          4, 3,     0,     1959,  4,  3,  7, ATP_TTDP_SMALL,    APC_SMALL,    STR_AIRPORT_SMALL,            SPR_AIRPORT_PREVIEW_SMALL),
 
	AS(city,             6, 6,  1955, MAX_YEAR,  5,  5, 24, ATP_TTDP_LARGE,    APC_LARGE,    STR_AIRPORT_CITY,             SPR_AIRPORT_PREVIEW_LARGE),
 
	AS_ND(heliport,      1, 1,  1963, MAX_YEAR,  4,  1,  4, ATP_TTDP_HELIPORT, APC_HELIPORT, STR_AIRPORT_HELIPORT,         SPR_AIRPORT_PREVIEW_HELIPORT),
 
	AS(metropolitan,     6, 6,  1980, MAX_YEAR,  6,  8, 28, ATP_TTDP_LARGE,    APC_LARGE,    STR_AIRPORT_METRO,            SPR_AIRPORT_PREVIEW_METROPOLITAN),
 
	AS(international,    7, 7,  1990, MAX_YEAR,  8, 17, 42, ATP_TTDP_LARGE,    APC_HUB,      STR_AIRPORT_INTERNATIONAL,    SPR_AIRPORT_PREVIEW_INTERNATIONAL),
 
	AS(commuter,         5, 4,  1983, MAX_YEAR,  4,  4, 20, ATP_TTDP_SMALL,    APC_SMALL,    STR_AIRPORT_COMMUTER,         SPR_AIRPORT_PREVIEW_COMMUTER),
 
	AS(helidepot,        2, 2,  1976, MAX_YEAR,  4,  2,  7, ATP_TTDP_SMALL,    APC_HELIPORT, STR_AIRPORT_HELIDEPOT,        SPR_AIRPORT_PREVIEW_HELIDEPOT),
 
	AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, 72, ATP_TTDP_LARGE,    APC_HUB,      STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL),
 
	AS(helistation,      4, 2,  1980, MAX_YEAR,  4,  3, 14, ATP_TTDP_SMALL,    APC_HELIPORT, STR_AIRPORT_HELISTATION,      SPR_AIRPORT_PREVIEW_HELISTATION),
 
	AS(city,             6, 6,  1955, CalendarTime::MAX_YEAR,  5,  5, 24, ATP_TTDP_LARGE,    APC_LARGE,    STR_AIRPORT_CITY,             SPR_AIRPORT_PREVIEW_LARGE),
 
	AS_ND(heliport,      1, 1,  1963, CalendarTime::MAX_YEAR,  4,  1,  4, ATP_TTDP_HELIPORT, APC_HELIPORT, STR_AIRPORT_HELIPORT,         SPR_AIRPORT_PREVIEW_HELIPORT),
 
	AS(metropolitan,     6, 6,  1980, CalendarTime::MAX_YEAR,  6,  8, 28, ATP_TTDP_LARGE,    APC_LARGE,    STR_AIRPORT_METRO,            SPR_AIRPORT_PREVIEW_METROPOLITAN),
 
	AS(international,    7, 7,  1990, CalendarTime::MAX_YEAR,  8, 17, 42, ATP_TTDP_LARGE,    APC_HUB,      STR_AIRPORT_INTERNATIONAL,    SPR_AIRPORT_PREVIEW_INTERNATIONAL),
 
	AS(commuter,         5, 4,  1983, CalendarTime::MAX_YEAR,  4,  4, 20, ATP_TTDP_SMALL,    APC_SMALL,    STR_AIRPORT_COMMUTER,         SPR_AIRPORT_PREVIEW_COMMUTER),
 
	AS(helidepot,        2, 2,  1976, CalendarTime::MAX_YEAR,  4,  2,  7, ATP_TTDP_SMALL,    APC_HELIPORT, STR_AIRPORT_HELIDEPOT,        SPR_AIRPORT_PREVIEW_HELIDEPOT),
 
	AS(intercontinental, 9, 11, 2002, CalendarTime::MAX_YEAR, 10, 25, 72, ATP_TTDP_LARGE,    APC_HUB,      STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL),
 
	AS(helistation,      4, 2,  1980, CalendarTime::MAX_YEAR,  4,  3, 14, ATP_TTDP_SMALL,    APC_HELIPORT, STR_AIRPORT_HELISTATION,      SPR_AIRPORT_PREVIEW_HELISTATION),
 
	AS_GENERIC(&_airportfta_oilrig, nullptr, _default_airports_rotation, 0, nullptr, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false),
 
};
 

	
 
static_assert(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs));
 

	
 
const AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, nullptr, _default_airports_rotation, 0, nullptr, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false);
 
const AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, nullptr, _default_airports_rotation, 0, nullptr, 0, 0, 0, 0, 0, CalendarTime::MIN_YEAR, CalendarTime::MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false);
 

	
 
#undef AS
 
#undef AS_ND
 
#undef AS_GENERIC
 

	
 
#endif /* AIRPORT_DEFAULTS_H */
src/table/engines.h
Show inline comments
 
@@ -3,111 +3,111 @@
 
 * 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.
 
 * 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.
 
 * 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/>.
 
 */
 

	
 
/**
 
 * @file table/engines.h
 
 *  This file contains all the data for vehicles
 
 */
 

	
 
#ifndef ENGINES_H
 
#define ENGINES_H
 

	
 
/**
 
 * Writes the properties of a train into the EngineInfo struct.
 
 * @see EngineInfo
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e cargo type
 
 * @param f Bitmask of the climates
 
 * @note the 5 between b and f is the load amount
 
 */
 
#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MT(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/**
 
 * Writes the properties of a multiple-unit train into the EngineInfo struct.
 
 * @see EngineInfo
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e cargo type
 
 * @param f Bitmask of the climates
 
 * @note the 5 between b and f is the load amount
 
 */
 
#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, Tick::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MM(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/**
 
 * Writes the properties of a train carriage into the EngineInfo struct.
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e cargo type
 
 * @param f Bitmask of the climates
 
 * @see MT
 
 * @note the 5 between b and f is the load amount
 
 */
 
#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Tick::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MW(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/**
 
 * Writes the properties of a road vehicle into the EngineInfo struct.
 
 * @see EngineInfo
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e cargo type
 
 * @param f Bitmask of the climates
 
 * @note the 5 between b and f is the load amount
 
 */
 
#define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Tick::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MR(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/**
 
 * Writes the properties of a ship into the EngineInfo struct.
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e cargo type
 
 * @param f Bitmask of the climates
 
 * @note the 10 between b and f is the load amount
 
 */
 
#define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Tick::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MS(a, b, c, d, e, f) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/**
 
 * Writes the properties of an aeroplane into the EngineInfo struct.
 
 * @param a base introduction date (days since 1920-01-01)
 
 * @param b decay speed
 
 * @param c life length (years)
 
 * @param d base life (years)
 
 * @param e Bitmask of the climates
 
 * @note the 20 between b and e is the load amount
 
 */
 
#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, Tick::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 
#define MA(a, b, c, d, e) { CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, Ticks::CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None }
 

	
 
/* Climates
 
 * T = Temperate
 
 * A = Sub-Arctic
 
 * S = Sub-Tropic
 
 * Y = Toyland */
 
#define T 1
 
#define A 2
 
#define S 4
 
#define Y 8
 
static const EngineInfo _orig_engine_info[] = {
 
	/*      base_intro     base_life
 
	 *      |    decay_speed         cargo_type
 
	 *      |    |    lifelength     |         climates
 
	 *      |    |    |    |         |         | */
 
	MT(  1827,  20,  15,  30, 0              , T      ), //   0 Kirby Paul Tank (Steam)
 
	MT( 12784,  20,  22,  30, 0              ,   A|S  ), //   1 MJS 250 (Diesel)
 
	MT(  9497,  20,  20,  50, 0              ,       Y), //   2 Ploddyphut Choo-Choo
 
	MT( 11688,  20,  20,  30, 0              ,       Y), //   3 Powernaut Choo-Choo
 
	MT( 16802,  20,  20,  30, 0              ,       Y), //   4 Mightymover Choo-Choo
 
	MT( 18993,  20,  20,  30, 0              ,       Y), //   5 Ploddyphut Diesel
 
	MT( 20820,  20,  20,  30, 0              ,       Y), //   6 Powernaut Diesel
 
	MT(  8766,  20,  20,  30, 0              ,   A|S  ), //   7 Wills 2-8-0 (Steam)
 
	MT(  5114,  20,  21,  30, 0              , T      ), //   8 Chaney 'Jubilee' (Steam)
src/table/object_land.h
Show inline comments
 
@@ -100,49 +100,49 @@ static const DrawTileSprites _object_hq[
 

	
 
	TILE_SPRITE_LINE(SPR_SMALLHQ_NORTH,        _object_nothing)
 
	TILE_SPRITE_LINE(SPR_SMALLHQ_WEST,         _object_nothing)
 
	TILE_SPRITE_LINE(SPR_SMALLHQ_EAST,         _object_nothing)
 
	TILE_SPRITE_LINE(SPR_SMALLHQ_SOUTH,        _object_nothing)
 

	
 
	TILE_SPRITE_LINE(SPR_MEDIUMHQ_NORTH,       _object_hq_medium_north)
 
	TILE_SPRITE_LINE(SPR_MEDIUMHQ_WEST,        _object_hq_medium_west)
 
	TILE_SPRITE_LINE(SPR_MEDIUMHQ_EAST,        _object_hq_medium_east)
 
	TILE_SPRITE_LINE(SPR_MEDIUMHQ_SOUTH,       _object_nothing)
 

	
 
	TILE_SPRITE_LINE(SPR_LARGEHQ_NORTH_GROUND, _object_hq_large_north)
 
	TILE_SPRITE_LINE(SPR_LARGEHQ_WEST_GROUND,  _object_hq_large_west)
 
	TILE_SPRITE_LINE(SPR_LARGEHQ_EAST_GROUND,  _object_hq_large_east)
 
	TILE_SPRITE_LINE(SPR_LARGEHQ_SOUTH,        _object_nothing)
 

	
 
	TILE_SPRITE_LINE(SPR_HUGEHQ_NORTH_GROUND,  _object_hq_huge_north)
 
	TILE_SPRITE_LINE(SPR_HUGEHQ_WEST_GROUND,   _object_hq_huge_west)
 
	TILE_SPRITE_LINE(SPR_HUGEHQ_EAST_GROUND,   _object_hq_huge_east)
 
	TILE_SPRITE_LINE(SPR_HUGEHQ_SOUTH,         _object_nothing)
 
};
 

	
 
#undef TILE_SPRITE_LINE
 

	
 
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), {0, 0, 0, 0}, INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DATE + 1, flags, 0, height, 1, gen_amount }
 
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), {0, 0, 0, 0}, INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, CalendarTime::MAX_DATE + 1, flags, 0, height, 1, gen_amount }
 

	
 
/* Climates
 
 * T = Temperate
 
 * A = Sub-Arctic
 
 * S = Sub-Tropic
 
 * Y = Toyland */
 
#define T 1
 
#define A 2
 
#define S 4
 
#define Y 8
 
/** Specification of the original object structures. */
 
extern const ObjectSpec _original_objects[] = {
 
	M(STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER,          0x11,   0,   0, 10, T|A|S  , 15, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT),
 
	M(STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE,           0x11,   0,   0,  8, T|A    ,  8, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT | OBJECT_FLAG_SCALE_BY_WATER),
 
	M(STR_TOWN_BUILDING_NAME_STATUE_1,                 0x11,   0,   0,  5, T|S|A|Y,  0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_ONLY_IN_SCENEDIT), // Yes, we disallow building this everywhere. Happens in "special" case!
 
	M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND,   0x11,  10,  10,  0, T|S|A|Y,  0, OBJECT_FLAG_AUTOREMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_CLEAR_INCOME | OBJECT_FLAG_HAS_NO_FOUNDATION ), // Only non-silly use case is to use it when you cannot build a station, so disallow bridges
 
	M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS, 0x22,   0,   0,  7, T|S|A|Y,  0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME),
 
};
 

	
 
#undef M
 
#undef Y
 
#undef S
 
#undef A
 
#undef T
src/table/railtypes.h
Show inline comments
 
@@ -78,49 +78,49 @@ static const RailtypeInfo _original_rail
 
		RTFB_NONE,
 

	
 
		/* cost multiplier */
 
		8,
 

	
 
		/* maintenance cost multiplier */
 
		8,
 

	
 
		/* acceleration type */
 
		0,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* rail type label */
 
		'RAIL',
 

	
 
		/* alternate labels */
 
		RailTypeLabelList(),
 

	
 
		/* map colour */
 
		0x0A,
 

	
 
		/* introduction date */
 
		INVALID_DATE,
 
		CalendarTime::INVALID_DATE,
 

	
 
		/* railtypes required for this to be introduced */
 
		RAILTYPES_NONE,
 

	
 
		/* introduction rail types */
 
		RAILTYPES_RAIL,
 

	
 
		/* sort order */
 
		0 << 4 | 7,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 

	
 
	/** Electrified railway */
 
	{ // Main Sprites
 
		{ SPR_RAIL_TRACK_Y, SPR_RAIL_TRACK_N_S, SPR_RAIL_TRACK_BASE, SPR_RAIL_SINGLE_X, SPR_RAIL_SINGLE_Y,
 
			SPR_RAIL_SINGLE_NORTH, SPR_RAIL_SINGLE_SOUTH, SPR_RAIL_SINGLE_EAST, SPR_RAIL_SINGLE_WEST,
 
			SPR_TRACKS_FOR_SLOPES_RAIL_BASE,
 
			SPR_CROSSING_OFF_X_RAIL,
 
			SPR_TUNNEL_ENTRY_REAR_RAIL
 
		},
 

	
 
		/* GUI sprites */
 
@@ -179,49 +179,49 @@ static const RailtypeInfo _original_rail
 
		RTFB_CATENARY,
 

	
 
		/* cost multiplier */
 
		12,
 

	
 
		/* maintenance cost multiplier */
 
		12,
 

	
 
		/* acceleration type */
 
		0,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* rail type label */
 
		'ELRL',
 

	
 
		/* alternate labels */
 
		RailTypeLabelList(),
 

	
 
		/* map colour */
 
		0x0A,
 

	
 
		/* introduction date */
 
		INVALID_DATE,
 
		CalendarTime::INVALID_DATE,
 

	
 
		/* railtypes required for this to be introduced */
 
		RAILTYPES_NONE,
 

	
 
		/* introduction rail types */
 
		RAILTYPES_ELECTRIC,
 

	
 
		/* sort order */
 
		1 << 4 | 7,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 

	
 
	/** Monorail */
 
	{ // Main Sprites
 
		{ SPR_MONO_TRACK_Y, SPR_MONO_TRACK_N_S, SPR_MONO_TRACK_BASE, SPR_MONO_SINGLE_X, SPR_MONO_SINGLE_Y,
 
			SPR_MONO_SINGLE_NORTH, SPR_MONO_SINGLE_SOUTH, SPR_MONO_SINGLE_EAST, SPR_MONO_SINGLE_WEST,
 
			SPR_TRACKS_FOR_SLOPES_MONO_BASE,
 
			SPR_CROSSING_OFF_X_MONO,
 
			SPR_TUNNEL_ENTRY_REAR_MONO
 
		},
 

	
 
		/* GUI sprites */
 
@@ -276,49 +276,49 @@ static const RailtypeInfo _original_rail
 
		RTFB_NONE,
 

	
 
		/* cost multiplier */
 
		16,
 

	
 
		/* maintenance cost multiplier */
 
		16,
 

	
 
		/* acceleration type */
 
		1,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* rail type label */
 
		'MONO',
 

	
 
		/* alternate labels */
 
		RailTypeLabelList(),
 

	
 
		/* map colour */
 
		0x0A,
 

	
 
		/* introduction date */
 
		INVALID_DATE,
 
		CalendarTime::INVALID_DATE,
 

	
 
		/* railtypes required for this to be introduced */
 
		RAILTYPES_NONE,
 

	
 
		/* introduction rail types */
 
		RAILTYPES_MONO,
 

	
 
		/* sort order */
 
		2 << 4 | 7,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 

	
 
	/** Maglev */
 
	{ // Main sprites
 
		{ SPR_MGLV_TRACK_Y, SPR_MGLV_TRACK_N_S, SPR_MGLV_TRACK_BASE, SPR_MGLV_SINGLE_X, SPR_MGLV_SINGLE_Y,
 
			SPR_MGLV_SINGLE_NORTH, SPR_MGLV_SINGLE_SOUTH, SPR_MGLV_SINGLE_EAST, SPR_MGLV_SINGLE_WEST,
 
			SPR_TRACKS_FOR_SLOPES_MAGLEV_BASE,
 
			SPR_CROSSING_OFF_X_MAGLEV,
 
			SPR_TUNNEL_ENTRY_REAR_MAGLEV
 
		},
 

	
 
		/* GUI sprites */
 
@@ -373,41 +373,41 @@ static const RailtypeInfo _original_rail
 
		RTFB_NONE,
 

	
 
		/* cost multiplier */
 
		24,
 

	
 
		/* maintenance cost multiplier */
 
		24,
 

	
 
		/* acceleration type */
 
		2,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* rail type label */
 
		'MGLV',
 

	
 
		/* alternate labels */
 
		RailTypeLabelList(),
 

	
 
		/* map colour */
 
		0x0A,
 

	
 
		/* introduction date */
 
		INVALID_DATE,
 
		CalendarTime::INVALID_DATE,
 

	
 
		/* railtypes required for this to be introduced */
 
		RAILTYPES_NONE,
 

	
 
		/* introduction rail types */
 
		RAILTYPES_MAGLEV,
 

	
 
		/* sort order */
 
		3 << 4 | 7,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 
};
 

	
 
#endif /* RAILTYPES_H */
src/table/roadtypes.h
Show inline comments
 
@@ -61,49 +61,49 @@ static const RoadTypeInfo _original_road
 
		ROADTYPES_ROAD,
 

	
 
		/* flags */
 
		ROTFB_TOWN_BUILD,
 

	
 
		/* cost multiplier */
 
		8,
 

	
 
		/* maintenance cost multiplier */
 
		16,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* road type label */
 
		'ROAD',
 

	
 
		/* alternate labels */
 
		RoadTypeLabelList(),
 

	
 
		/* map colour */
 
		0x01,
 

	
 
		/* introduction date */
 
		static_cast<int32_t>(MIN_YEAR),
 
		static_cast<int32_t>(CalendarTime::MIN_YEAR),
 

	
 
		/* roadtypes required for this to be introduced */
 
		ROADTYPES_NONE,
 

	
 
		/* introduction road types */
 
		ROADTYPES_ROAD,
 

	
 
		/* sort order */
 
		0x07,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 

	
 
	/* Electrified Tram */
 
	{
 
		/* GUI sprites */
 
		{
 
			SPR_IMG_TRAMWAY_X_DIR,
 
			SPR_IMG_TRAMWAY_Y_DIR,
 
			SPR_IMG_AUTOTRAM,
 
			SPR_IMG_ROAD_DEPOT,
 
			SPR_IMG_ROAD_TUNNEL,
 
			SPR_IMG_CONVERT_TRAM,
 
@@ -141,41 +141,41 @@ static const RoadTypeInfo _original_road
 
		ROADTYPES_TRAM,
 

	
 
		/* flags */
 
		ROTFB_CATENARY | ROTFB_NO_HOUSES,
 

	
 
		/* cost multiplier */
 
		16,
 

	
 
		/* maintenance cost multiplier */
 
		24,
 

	
 
		/* max speed */
 
		0,
 

	
 
		/* road type label */
 
		'ELRL',
 

	
 
		/* alternate labels */
 
		RoadTypeLabelList(),
 

	
 
		/* map colour */
 
		0x01,
 

	
 
		/* introduction date */
 
		INVALID_DATE,
 
		CalendarTime::INVALID_DATE,
 

	
 
		/* roadtypes required for this to be introduced */
 
		ROADTYPES_NONE,
 

	
 
		/* introduction road types */
 
		ROADTYPES_TRAM,
 

	
 
		/* sort order */
 
		0x17,
 

	
 
		{ nullptr },
 
		{ nullptr },
 
	},
 
};
 

	
 
#endif /* ROADTYPES_H */
src/table/settings/currency_settings.ini
Show inline comments
 
@@ -29,36 +29,36 @@ load     = nullptr
 
from     = SL_MIN_VERSION
 
to       = SL_MAX_VERSION
 
cat      = SC_ADVANCED
 
extra    = 0
 
startup  = false
 

	
 

	
 
[SDT_VAR]
 
var      = rate
 
type     = SLE_UINT16
 
def      = 1
 
min      = 0
 
max      = UINT16_MAX
 

	
 
[SDT_SSTR]
 
var      = separator
 
type     = SLE_STRQ
 
def      = "".""
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = to_euro
 
type     = SLE_INT32
 
def      = 0
 
min      = MIN_YEAR
 
max      = MAX_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR
 

	
 
[SDT_SSTR]
 
var      = prefix
 
type     = SLE_STRQ
 
def      = nullptr
 

	
 
[SDT_SSTR]
 
var      = suffix
 
type     = SLE_STRQ
 
def      = "" credits""
src/table/settings/gui_settings.ini
Show inline comments
 
@@ -475,97 +475,97 @@ var      = gui.signal_gui_mode
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 0
 
min      = 0
 
max      = 1
 
str      = STR_CONFIG_SETTING_SIGNAL_GUI_MODE
 
strhelp  = STR_CONFIG_SETTING_SIGNAL_GUI_MODE_HELPTEXT
 
strval   = STR_CONFIG_SETTING_SIGNAL_GUI_MODE_PATH
 
post_cb  = [](auto) { CloseWindowByClass(WC_BUILD_SIGNAL); }
 
cat      = SC_ADVANCED
 

	
 
[SDTC_VAR]
 
var      = gui.default_signal_type
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = 5
 
min      = 0
 
max      = 5
 

	
 
[SDTC_VAR]
 
var      = gui.coloured_news_year
 
type     = SLE_INT32
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = 2000
 
min      = MIN_YEAR
 
max      = MAX_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR
 
interval = 1
 
str      = STR_CONFIG_SETTING_COLOURED_NEWS_YEAR
 
strhelp  = STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT
 
strval   = STR_JUST_INT
 
cat      = SC_EXPERT
 

	
 
[SDTC_VAR]
 
var      = gui.cycle_signal_types
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 0
 
min      = 0
 
max      = 1
 
interval = 1
 
str      = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES
 
strhelp  = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT
 
strval   = STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS
 
cat      = SC_ADVANCED
 

	
 
[SDTC_VAR]
 
var      = gui.drag_signals_density
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = 4
 
min      = 1
 
max      = 20
 
str      = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY
 
strhelp  = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT
 
strval   = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE
 
post_cb  = [](auto) { InvalidateWindowData(WC_BUILD_SIGNAL, 0); }
 
cat      = SC_BASIC
 

	
 
[SDTC_BOOL]
 
var      = gui.drag_signals_fixed_distance
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = false
 
str      = STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE
 
strhelp  = STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT
 
cat      = SC_EXPERT
 

	
 
[SDTC_VAR]
 
var      = gui.semaphore_build_before
 
type     = SLE_INT32
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = 1950
 
min      = MIN_YEAR
 
max      = MAX_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR
 
interval = 1
 
str      = STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE
 
strhelp  = STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT
 
strval   = STR_JUST_INT
 
post_cb  = ResetSignalVariant
 

	
 
[SDTC_BOOL]
 
var      = gui.vehicle_income_warn
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC
 
def      = true
 
str      = STR_CONFIG_SETTING_WARN_INCOME_LESS
 
strhelp  = STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT
 
cat      = SC_BASIC
 

	
 
[SDTC_VAR]
 
var      = gui.order_review_system
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN
 
def      = 2
 
min      = 0
 
max      = 2
 
str      = STR_CONFIG_SETTING_ORDER_REVIEW
 
strhelp  = STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT
 
strval   = STR_CONFIG_SETTING_ORDER_REVIEW_OFF
src/table/settings/network_settings.ini
Show inline comments
 
@@ -216,41 +216,41 @@ max      = 240
 
var      = network.max_companies
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
 
def      = 15
 
min      = 1
 
max      = MAX_COMPANIES
 
post_cb  = [](auto) { UpdateClientConfigValues(); }
 
cat      = SC_BASIC
 

	
 
[SDTC_VAR]
 
var      = network.max_clients
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
 
def      = 25
 
min      = 2
 
max      = MAX_CLIENTS
 
post_cb  = [](auto) { UpdateClientConfigValues(); }
 
cat      = SC_BASIC
 

	
 
[SDTC_VAR]
 
var      = network.restart_game_year
 
type     = SLE_INT32
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_0_IS_SPECIAL | SF_NETWORK_ONLY
 
def      = 0
 
min      = MIN_YEAR
 
max      = MAX_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR
 
interval = 1
 

	
 
[SDTC_VAR]
 
var      = network.min_active_clients
 
type     = SLE_UINT8
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
 
def      = 0
 
min      = 0
 
max      = MAX_CLIENTS
 

	
 
[SDTC_BOOL]
 
var      = network.reload_cfg
 
flags    = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_NETWORK_ONLY
 
def      = false
 
cat      = SC_EXPERT
src/table/settings/world_settings.ini
Show inline comments
 
@@ -101,64 +101,64 @@ min      = 0
 
max      = 100
 
interval = 10
 
str      = STR_CONFIG_SETTING_SNOW_COVERAGE
 
strhelp  = STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
 
strval   = STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = game_creation.desert_coverage
 
type     = SLE_UINT8
 
from     = SLV_MAPGEN_SETTINGS_REVAMP
 
flags    = SF_NEWGAME_ONLY
 
def      = DEF_DESERT_COVERAGE
 
min      = 0
 
max      = 100
 
interval = 10
 
str      = STR_CONFIG_SETTING_DESERT_COVERAGE
 
strhelp  = STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
 
strval   = STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = game_creation.starting_year
 
type     = SLE_INT32
 
def      = DEF_START_YEAR
 
min      = MIN_YEAR
 
max      = MAX_YEAR
 
def      = CalendarTime::DEF_START_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR
 
interval = 1
 
str      = STR_CONFIG_SETTING_STARTING_YEAR
 
strval   = STR_JUST_INT
 
cat      = SC_BASIC
 

	
 
[SDT_VAR]
 
var      = game_creation.ending_year
 
type     = SLE_INT32
 
from     = SLV_ENDING_YEAR
 
flags    = SF_GUI_0_IS_SPECIAL
 
def      = DEF_END_YEAR
 
min      = MIN_YEAR
 
max      = MAX_YEAR - 1
 
def      = CalendarTime::DEF_END_YEAR
 
min      = CalendarTime::MIN_YEAR
 
max      = CalendarTime::MAX_YEAR - 1
 
interval = 1
 
str      = STR_CONFIG_SETTING_ENDING_YEAR
 
strhelp  = STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT
 
strval   = STR_CONFIG_SETTING_ENDING_YEAR_VALUE
 
cat      = SC_ADVANCED
 

	
 
[SDT_VAR]
 
var      = game_creation.land_generator
 
type     = SLE_UINT8
 
from     = SLV_30
 
flags    = SF_GUI_DROPDOWN | SF_NEWGAME_ONLY
 
def      = 1
 
min      = 0
 
max      = 1
 
str      = STR_CONFIG_SETTING_LAND_GENERATOR
 
strhelp  = STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT
 
strval   = STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL
 

	
 
[SDT_VAR]
 
var      = game_creation.oil_refinery_limit
 
type     = SLE_UINT8
 
from     = SLV_30
 
def      = 32
 
min      = 12
src/table/town_land.h
Show inline comments
 
@@ -1800,480 +1800,480 @@ static_assert(lengthof(_town_draw_tile_d
 
 * @param rr  rating decrease if removed
 
 * @param mg  mail generation multiplier
 
 * @param ca1 acceptance for 1st CargoID
 
 * @param ca2 acceptance for 2nd CargoID
 
 * @param ca3 acceptance for 3rd CargoID
 
 * @param bf  building flags (size, stadium etc...)
 
 * @param ba  building availability (zone, climate...)
 
 * @param cg1 1st CargoID available
 
 * @param cg2 2nd CargoID available
 
 * @param cg3 3rd CargoID available
 
 * @see HouseSpec
 
 */
 
#define MS(mnd, mxd, p, rc, bn, rr, mg, ca1, ca2, ca3, bf, ba, cg1, cg2, cg3) \
 
	{mnd, mxd, p, rc, bn, rr, mg, \
 
	{ca1, ca2, ca3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \
 
	{cg1, cg2, cg3, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, \
 
	bf, ba, true, GRFFileProps(INVALID_HOUSE_ID), 0, {0, 0, 0, 0}, \
 
	16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0}
 
/** House specifications from original data */
 
static const HouseSpec _original_house_specs[] = {
 
	/**
 
	 *                                                                              remove_rating_decrease
 
	 *                                                                              |    mail_generation
 
	 *     min_year                                                                 |    |    1st CargoID acceptance
 
	 *     |         max_year                                                       |    |    |    2nd CargoID acceptance
 
	 *     |         CalendarTime::MAX_YEAR                                                       |    |    |    2nd CargoID acceptance
 
	 *     |         |    population                                                |    |    |    |    3th CargoID acceptance
 
	 *     |         |    |    removal_cost                                         |    |    |    |    |
 
	 *     |         |    |    |    building_name                                   |    |    |    |    |
 
	 *     |         |    |    |    |                                               |    |    |    |    |
 
	 *     |         |    |    |    |                                               |    |    |    |    |
 
	 * +-building_flags   |    |    |                                               |    |    |    |    |
 
	 * +-building_availability |    |                                               |    |    |    |    |
 
	 * +-cargoID accepted |    |    |                                               |    |    |    |    |
 
	 * |   |         |    |    |    |                                               |    |    |    |    |
 
	 */
 
	MS(1963, MAX_YEAR, 187, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  70,   8,   3,   4,
 
	MS(1963, CalendarTime::MAX_YEAR, 187, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  70,   8,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 00
 
	MS(1957, MAX_YEAR,  85, 140, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1,           130,  55,   8,   3,   4,
 
	MS(1957, CalendarTime::MAX_YEAR,  85, 140, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1,           130,  55,   8,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 01
 
	MS(1968, MAX_YEAR,  40, 100, STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1,    90,  20,   8,   3,   1,
 
	MS(1968, CalendarTime::MAX_YEAR,  40, 100, STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1,    90,  20,   8,   3,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 02
 
	MS(   0, MAX_YEAR,   5,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   5,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	   BUILDING_IS_CHURCH | TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 03
 
	MS(1975, MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1,     160,  85,  10,   4,   6,
 
	MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1,     160,  85,  10,   4,   6,
 
	   BUILDING_IS_ANIMATED | TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 04
 
	MS(1975, MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1,     160,  85,  10,   4,   6,
 
	MS(1975, CalendarTime::MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1,     160,  85,  10,   4,   6,
 
	   BUILDING_IS_ANIMATED | TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE  | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 05
 
	MS(   0, MAX_YEAR,  30,  80, STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1,             80,  12,   4,   1,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,  30,  80, STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1,             80,  12,   4,   1,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 06
 
	MS(1959, MAX_YEAR, 140, 180, STR_TOWN_BUILDING_NAME_HOTEL_1,                  150,  22,   6,   1,   2,
 
	MS(1959, CalendarTime::MAX_YEAR, 140, 180, STR_TOWN_BUILDING_NAME_HOTEL_1,                  150,  22,   6,   1,   2,
 
	   TILE_SIZE_1x2,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 07
 
	MS(1959, MAX_YEAR,   0, 180, STR_TOWN_BUILDING_NAME_HOTEL_1,                  150,  22,   6,   1,   2,
 
	MS(1959, CalendarTime::MAX_YEAR,   0, 180, STR_TOWN_BUILDING_NAME_HOTEL_1,                  150,  22,   6,   1,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 08
 
	MS(1945, MAX_YEAR,   0,  65, STR_TOWN_BUILDING_NAME_STATUE_1,                  40,   0,   2,   0,   0,
 
	MS(1945, CalendarTime::MAX_YEAR,   0,  65, STR_TOWN_BUILDING_NAME_STATUE_1,                  40,   0,   2,   0,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 09
 
	MS(1945, MAX_YEAR,   0,  65, STR_TOWN_BUILDING_NAME_FOUNTAIN_1,                40,   0,   2,   0,   0,
 
	MS(1945, CalendarTime::MAX_YEAR,   0,  65, STR_TOWN_BUILDING_NAME_FOUNTAIN_1,                40,   0,   2,   0,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0A
 
	MS(   0, MAX_YEAR,   0,  60, STR_TOWN_BUILDING_NAME_PARK_1,                    75,   0,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   0,  60, STR_TOWN_BUILDING_NAME_PARK_1,                    75,   0,   2,   0,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0B
 
	MS(1935, MAX_YEAR,   0,  60, STR_TOWN_BUILDING_NAME_PARK_1,                    75,   0,   2,   0,   0,
 
	MS(1935, CalendarTime::MAX_YEAR,   0,  60, STR_TOWN_BUILDING_NAME_PARK_1,                    75,   0,   2,   0,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0C
 
	MS(1951, MAX_YEAR, 150, 130, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2,           110,  65,   8,   2,   4,
 
	MS(1951, CalendarTime::MAX_YEAR, 150, 130, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2,           110,  65,   8,   2,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0D
 
	MS(1930, 1960,      95, 110, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      100,  48,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0E
 
	MS(1930, 1960,      95, 105, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      100,  48,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0F
 
	MS(1930, 1960,      95, 107, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      100,  48,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 10
 
	MS(1977, MAX_YEAR, 130, 200, STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1, 150,  50,  10,   3,   6,
 
	MS(1977, CalendarTime::MAX_YEAR, 130, 200, STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1, 150,  50,  10,   3,   6,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 11
 
	MS(1983, MAX_YEAR,   6, 145, STR_TOWN_BUILDING_NAME_WAREHOUSE_1,              110,  10,   6,   3,   8,
 
	MS(1983, CalendarTime::MAX_YEAR,   6, 145, STR_TOWN_BUILDING_NAME_WAREHOUSE_1,              110,  10,   6,   3,   8,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 12
 
	MS(1985, MAX_YEAR, 110, 155, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3,           110,  55,   6,   2,   6,
 
	MS(1985, CalendarTime::MAX_YEAR, 110, 155, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3,           110,  55,   6,   2,   6,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 13
 
	MS(   0, MAX_YEAR,  65, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,  65, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	   BUILDING_IS_STADIUM | TILE_SIZE_2x2,
 
	   HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 14
 
	MS(   0, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 15
 
	MS(   0, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 16
 
	MS(   0, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 17
 
	MS(   0, 1951,      15,  70, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1,              75,   6,   3,   1,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 18
 
	MS(   0, 1952,      12,  75, STR_TOWN_BUILDING_NAME_COTTAGES_1,                75,   7,   3,   1,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 19
 
	MS(1931, MAX_YEAR,  13,  71, STR_TOWN_BUILDING_NAME_HOUSES_1,                  75,   8,   3,   1,   0,
 
	MS(1931, CalendarTime::MAX_YEAR,  13,  71, STR_TOWN_BUILDING_NAME_HOUSES_1,                  75,   8,   3,   1,   0,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1A
 
	MS(1935, MAX_YEAR, 100, 135, STR_TOWN_BUILDING_NAME_FLATS_1,                  100,  35,   7,   2,   2,
 
	MS(1935, CalendarTime::MAX_YEAR, 100, 135, STR_TOWN_BUILDING_NAME_FLATS_1,                  100,  35,   7,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1B
 
	MS(1963, MAX_YEAR, 170, 145, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2,      170,  50,   8,   3,   3,
 
	MS(1963, CalendarTime::MAX_YEAR, 170, 145, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2,      170,  50,   8,   3,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1C
 
	MS(   0, 1955,     100, 132, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2,      135,  40,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1D
 
	MS(1973, MAX_YEAR, 180, 155, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3,      180,  64,   8,   3,   3,
 
	MS(1973, CalendarTime::MAX_YEAR, 180, 155, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3,      180,  64,   8,   3,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1E
 
	MS(   0, MAX_YEAR,  35, 220, STR_TOWN_BUILDING_NAME_THEATER_1,                230,  23,   8,   2,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  35, 220, STR_TOWN_BUILDING_NAME_THEATER_1,                230,  23,   8,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1F
 
	MS(1958, MAX_YEAR,  65, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	MS(1958, CalendarTime::MAX_YEAR,  65, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	   BUILDING_IS_STADIUM | TILE_SIZE_2x2,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 20
 
	MS(1958, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	MS(1958, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 21
 
	MS(1958, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	MS(1958, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 22
 
	MS(1958, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	MS(1958, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2,                300,   5,   4,   0,   0,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 23
 
	MS(2000, MAX_YEAR, 140, 170, STR_TOWN_BUILDING_NAME_OFFICES_1,                250,  65,   8,   3,   2,
 
	MS(2000, CalendarTime::MAX_YEAR, 140, 170, STR_TOWN_BUILDING_NAME_OFFICES_1,                250,  65,   8,   3,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 24
 
	MS(   0, 1960,      15,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 25
 
	MS(   0, 1960,      15,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 26
 
	MS(1945, MAX_YEAR,  35, 210, STR_TOWN_BUILDING_NAME_CINEMA_1,                 230,  23,   8,   2,   2,
 
	MS(1945, CalendarTime::MAX_YEAR,  35, 210, STR_TOWN_BUILDING_NAME_CINEMA_1,                 230,  23,   8,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 27
 
	MS(1983, MAX_YEAR, 180, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	MS(1983, CalendarTime::MAX_YEAR, 180, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	   TILE_SIZE_2x2,
 
	   HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 |HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 28
 
	MS(1983, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	MS(1983, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 29
 
	MS(1983, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	MS(1983, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2A
 
	MS(1983, MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	MS(1983, CalendarTime::MAX_YEAR,   0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1,          300,   5,   8,   2,   3,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2B
 
	MS(   0, MAX_YEAR,  80, 100, STR_TOWN_BUILDING_NAME_FLATS_1,                   90,  20,   5,   2,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  80, 100, STR_TOWN_BUILDING_NAME_FLATS_1,                   90,  20,   5,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2C
 
	MS(   0, MAX_YEAR,  80, 100, STR_TOWN_BUILDING_NAME_FLATS_1,                   90,  20,   5,   2,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  80, 100, STR_TOWN_BUILDING_NAME_FLATS_1,                   90,  20,   5,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE  | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2D
 
	MS(   0, MAX_YEAR,  16,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  16,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2E
 
	MS(   0, MAX_YEAR,  16,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  16,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2F
 
	MS(   0, 1963,      14,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 30
 
	MS(   0, 1963,      14,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  70,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 31
 
	MS(1966, MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      120,  60,   8,   3,   4,
 
	MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      120,  60,   8,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 32
 
	MS(1966, MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      120,  60,   8,   3,   4,
 
	MS(1966, CalendarTime::MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      120,  60,   8,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 33
 
	MS(1970, MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  70,   9,   3,   4,
 
	MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  70,   9,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 34
 
	MS(1970, MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  70,   9,   3,   4,
 
	MS(1970, CalendarTime::MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  70,   9,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 35
 
	MS(1974, MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,  10,   3,   5,
 
	MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,  10,   3,   5,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 36
 
	MS(1974, MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,  10,   3,   5,
 
	MS(1974, CalendarTime::MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,  10,   3,   5,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 37
 
	MS(   0, MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_HOUSES_2,                  60,   5,   2,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_HOUSES_2,                  60,   5,   2,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 38
 
	MS(   0, MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_HOUSES_2,                  60,   5,   2,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_HOUSES_2,                  60,   5,   2,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 39
 
	MS(   0, MAX_YEAR,  25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,       80,  20,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,       80,  20,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3A
 
	MS(   0, MAX_YEAR,  25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,       80,  20,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,       80,  20,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3B
 
	MS(   0, MAX_YEAR,   6,  85, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   6,  85, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	   BUILDING_IS_CHURCH | TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3C
 
	MS(   0, MAX_YEAR,   6,  85, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   6,  85, STR_TOWN_BUILDING_NAME_CHURCH_1,                 230,   2,   2,   0,   0,
 
	   BUILDING_IS_CHURCH | TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3D
 
	MS(   0, MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3E
 
	MS(   0, MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3F
 
	MS(   0, 1960,      90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      110,  45,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 40
 
	MS(   0, 1960,      90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      110,  45,   6,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 41
 
	MS(1972, MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   3,
 
	MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   3,
 
	   TILE_SIZE_1x2,
 
	   HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 42
 
	MS(1972, MAX_YEAR,   0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   2,
 
	MS(1972, CalendarTime::MAX_YEAR,   0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 43
 
	MS(1972, MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   3,
 
	MS(1972, CalendarTime::MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   3,
 
	   TILE_SIZE_1x2,
 
	   HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 44
 
	MS(1972, MAX_YEAR,   0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   2,
 
	MS(1972, CalendarTime::MAX_YEAR,   0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1,                  160,  25,   6,   1,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 45
 
	MS(1963, MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      105,  50,   7,   2,   3,
 
	MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      105,  50,   7,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 46
 
	MS(1963, MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      105,  50,   7,   2,   3,
 
	MS(1963, CalendarTime::MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      105,  50,   7,   2,   3,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 47
 
	MS(1978, MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      135,  75,   9,   3,   4,
 
	MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      135,  75,   9,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 48
 
	MS(1978, MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      135,  75,   9,   3,   4,
 
	MS(1978, CalendarTime::MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      135,  75,   9,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 49
 
	MS(1967, MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	   TILE_SIZE_2x1,
 
	   HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4A
 
	MS(1967, MAX_YEAR,   0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	MS(1967, CalendarTime::MAX_YEAR,   0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4B
 
	MS(1967, MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	MS(1967, CalendarTime::MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	   TILE_SIZE_2x1,
 
	   HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4C
 
	MS(1967, MAX_YEAR,   0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	MS(1967, CalendarTime::MAX_YEAR,   0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      200,  60,   7,   2,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4D
 
	MS(   0, MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4E
 
	MS(   0, MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4F
 
	MS(   0, MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   5,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  16,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   5,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 50
 
	MS(   0, MAX_YEAR,   7,  30, STR_TOWN_BUILDING_NAME_HOUSES_2,                  30,   4,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,   7,  30, STR_TOWN_BUILDING_NAME_HOUSES_2,                  30,   4,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 51
 
	MS(   0, MAX_YEAR,  45, 130, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  15,   6,   2,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  45, 130, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  15,   6,   2,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 52
 
	MS(   0, MAX_YEAR,   8,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 200,   3,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   8,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 200,   3,   2,   0,   0,
 
	   BUILDING_IS_CHURCH | TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 53
 
	MS(   0, MAX_YEAR,  18,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  18,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   7,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2,
 
	   CT_PASSENGERS, CT_MAIL, CT_FOOD), // 54
 
	MS(1973, MAX_YEAR,  90, 110, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  24,   6,   2,   1,
 
	MS(1973, CalendarTime::MAX_YEAR,  90, 110, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  24,   6,   2,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 55
 
	MS(1962, MAX_YEAR, 120, 120, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  25,   6,   2,   1,
 
	MS(1962, CalendarTime::MAX_YEAR, 120, 120, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  25,   6,   2,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 56
 
	MS(1984, MAX_YEAR, 250, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,   8,   3,   4,
 
	MS(1984, CalendarTime::MAX_YEAR, 250, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,   8,   3,   4,
 
	   TILE_SIZE_2x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 57
 
	MS(1984, MAX_YEAR,   0, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,   8,   3,   4,
 
	MS(1984, CalendarTime::MAX_YEAR,   0, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      140,  80,   8,   3,   4,
 
	   TILE_NO_FLAG,
 
	   HZ_SUBTROPIC,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 58
 
	MS(   0, MAX_YEAR,  80, 110, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  23,   6,   2,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  80, 110, STR_TOWN_BUILDING_NAME_FLATS_1,                   95,  23,   6,   2,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 59
 
	MS(1993, MAX_YEAR, 180, 180, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      150,  90,   8,   3,   4,
 
	MS(1993, CalendarTime::MAX_YEAR, 180, 180, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      150,  90,   8,   3,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_GOODS), // 5A
 
	MS(   0, MAX_YEAR,   8,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 200,   3,   2,   0,   0,
 
	MS(   0, CalendarTime::MAX_YEAR,   8,  90, STR_TOWN_BUILDING_NAME_CHURCH_1,                 200,   3,   2,   0,   0,
 
	   BUILDING_IS_CHURCH | TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5B
 
	MS(   0, MAX_YEAR,  18,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  90,   5,   6,   2,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  18,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  90,   5,   6,   2,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5C
 
	MS(   0, MAX_YEAR,   7,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  50,   3,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,   7,  70, STR_TOWN_BUILDING_NAME_HOUSES_2,                  50,   3,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5D
 
	MS(   0, MAX_YEAR,  15,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  15,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5E
 
	MS(   0, MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  17,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5F
 
	MS(   0, MAX_YEAR,  19,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  19,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 60
 
	MS(   0, MAX_YEAR,  21,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  21,  80, STR_TOWN_BUILDING_NAME_HOUSES_2,                  75,   6,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 61
 
	MS(   0, MAX_YEAR,  75, 160, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  20,   8,   4,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  75, 160, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  20,   8,   4,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 62
 
	MS(   0, MAX_YEAR,  35,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   9,   4,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  35,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   9,   4,   1,   2,
 
	   TILE_SIZE_1x2,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 63
 
	MS(   0, MAX_YEAR,   0,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   0,   4,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,   0,  90, STR_TOWN_BUILDING_NAME_HOUSES_2,                  80,   0,   4,   1,   2,
 
	   TILE_NO_FLAG,
 
	   HZ_NOZNS,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 64
 
	MS(   0, MAX_YEAR,  85, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  18,   8,   4,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  85, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  18,   8,   4,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 65
 
	MS(   0, MAX_YEAR,  11,  60, STR_TOWN_BUILDING_NAME_IGLOO_1,                   45,   3,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  11,  60, STR_TOWN_BUILDING_NAME_IGLOO_1,                   45,   3,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 66
 
	MS(   0, MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_TEPEES_1,                  45,   3,   3,   1,   1,
 
	MS(   0, CalendarTime::MAX_YEAR,  10,  60, STR_TOWN_BUILDING_NAME_TEPEES_1,                  45,   3,   3,   1,   1,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 67
 
	MS(   0, MAX_YEAR,  67, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      130,  22,   8,   4,   4,
 
	MS(   0, CalendarTime::MAX_YEAR,  67, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      130,  22,   8,   4,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 68
 
	MS(   0, MAX_YEAR,  86, 145, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      130,  23,   8,   4,   4,
 
	MS(   0, CalendarTime::MAX_YEAR,  86, 145, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1,      130,  23,   8,   4,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 69
 
	MS(   0, MAX_YEAR,  95, 165, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  28,   8,   4,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  95, 165, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1,      130,  28,   8,   4,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6A
 
	MS(   0, MAX_YEAR,  30,  90, STR_TOWN_BUILDING_NAME_STATUE_1,                  70,  10,   4,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  30,  90, STR_TOWN_BUILDING_NAME_STATUE_1,                  70,  10,   4,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6B
 
	MS(   0, MAX_YEAR,  25,  75, STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1,            65,   8,   3,   1,   2,
 
	MS(   0, CalendarTime::MAX_YEAR,  25,  75, STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1,            65,   8,   3,   1,   2,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6C
 
	MS(   0, MAX_YEAR,  18,  85, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1,              95,   7,   3,   2,   4,
 
	MS(   0, CalendarTime::MAX_YEAR,  18,  85, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1,              95,   7,   3,   2,   4,
 
	   TILE_SIZE_1x1,
 
	   HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1,
 
	   CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 6D
 
};
 
#undef MS
 

	
 
/** Make sure we have the right number of elements: one entry for each house */
 
static_assert(lengthof(_original_house_specs) == NEW_HOUSE_OFFSET);
src/timer/timer_game_calendar.cpp
Show inline comments
 
@@ -47,134 +47,134 @@ enum DaysTillMonth {
 
	ACCUM_MAR = ACCUM_FEB + 29,
 
	ACCUM_APR = ACCUM_MAR + 31,
 
	ACCUM_MAY = ACCUM_APR + 30,
 
	ACCUM_JUN = ACCUM_MAY + 31,
 
	ACCUM_JUL = ACCUM_JUN + 30,
 
	ACCUM_AUG = ACCUM_JUL + 31,
 
	ACCUM_SEP = ACCUM_AUG + 31,
 
	ACCUM_OCT = ACCUM_SEP + 30,
 
	ACCUM_NOV = ACCUM_OCT + 31,
 
	ACCUM_DEC = ACCUM_NOV + 30,
 
};
 

	
 
/** Number of days to pass from the first day in the year before reaching the first of a month. */
 
static const uint16_t _accum_days_for_month[] = {
 
	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
 
	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
 
	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
 
};
 

	
 
/**
 
 * Converts a Date to a Year, Month & Day.
 
 * @param date the date to convert from
 
 * @param ymd  the year, month and day to write to
 
 */
 
/* static */ void TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date, YearMonthDay *ymd)
 
/* static */ void TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date, TimerGameCalendar::YearMonthDay *ymd)
 
{
 
	/* Year determination in multiple steps to account for leap
 
	 * years. First do the large steps, then the smaller ones.
 
	 */
 

	
 
	/* There are 97 leap years in 400 years */
 
	TimerGameCalendar::Year yr = 400 * (static_cast<int32_t>(date) / (DAYS_IN_YEAR * 400 + 97));
 
	int rem = static_cast<int32_t>(date) % (DAYS_IN_YEAR * 400 + 97);
 
	TimerGameCalendar::Year yr = 400 * (static_cast<int32_t>(date) / (CalendarTime::DAYS_IN_YEAR * 400 + 97));
 
	int rem = static_cast<int32_t>(date) % (CalendarTime::DAYS_IN_YEAR * 400 + 97);
 
	uint16_t x;
 

	
 
	if (rem >= DAYS_IN_YEAR * 100 + 25) {
 
	if (rem >= CalendarTime::DAYS_IN_YEAR * 100 + 25) {
 
		/* There are 25 leap years in the first 100 years after
 
		 * every 400th year, as every 400th year is a leap year */
 
		yr += 100;
 
		rem -= DAYS_IN_YEAR * 100 + 25;
 
		rem -= CalendarTime::DAYS_IN_YEAR * 100 + 25;
 

	
 
		/* There are 24 leap years in the next couple of 100 years */
 
		yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
 
		rem = (rem % (DAYS_IN_YEAR * 100 + 24));
 
		yr += 100 * (rem / (CalendarTime::DAYS_IN_YEAR * 100 + 24));
 
		rem = (rem % (CalendarTime::DAYS_IN_YEAR * 100 + 24));
 
	}
 

	
 
	if (!TimerGameCalendar::IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
 
	if (!TimerGameCalendar::IsLeapYear(yr) && rem >= CalendarTime::DAYS_IN_YEAR * 4) {
 
		/* The first 4 year of the century are not always a leap year */
 
		yr += 4;
 
		rem -= DAYS_IN_YEAR * 4;
 
		rem -= CalendarTime::DAYS_IN_YEAR * 4;
 
	}
 

	
 
	/* There is 1 leap year every 4 years */
 
	yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
 
	rem = rem % (DAYS_IN_YEAR * 4 + 1);
 
	yr += 4 * (rem / (CalendarTime::DAYS_IN_YEAR * 4 + 1));
 
	rem = rem % (CalendarTime::DAYS_IN_YEAR * 4 + 1);
 

	
 
	/* The last (max 3) years to account for; the first one
 
	 * can be, but is not necessarily a leap year */
 
	while (rem >= (TimerGameCalendar::IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
 
		rem -= TimerGameCalendar::IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
 
	while (rem >= (TimerGameCalendar::IsLeapYear(yr) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR)) {
 
		rem -= TimerGameCalendar::IsLeapYear(yr) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
 
		yr++;
 
	}
 

	
 
	/* Skip the 29th of February in non-leap years */
 
	if (!TimerGameCalendar::IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
 

	
 
	ymd->year = yr;
 

	
 
	x = _month_date_from_year_day[rem];
 
	ymd->month = x >> 5;
 
	ymd->day = x & 0x1F;
 
}
 

	
 
/**
 
 * Converts a tuple of Year, Month and Day to a Date.
 
 * @param year  is a number between 0..MAX_YEAR
 
 * @param month is a number between 0..11
 
 * @param day   is a number between 1..31
 
 */
 
/* static */ TimerGameCalendar::Date TimerGameCalendar::ConvertYMDToDate(TimerGameCalendar::Year year, TimerGameCalendar::Month month, TimerGameCalendar::Day day)
 
{
 
	/* Day-offset in a leap year */
 
	int days = _accum_days_for_month[month] + day - 1;
 

	
 
	/* Account for the missing of the 29th of February in non-leap years */
 
	if (!TimerGameCalendar::IsLeapYear(year) && days >= ACCUM_MAR) days--;
 

	
 
	return DateAtStartOfYear(year) + days;
 
	return TimerGameCalendar::DateAtStartOfYear(year) + days;
 
}
 

	
 
/**
 
 * Checks whether the given year is a leap year or not.
 
 * @param yr The year to check.
 
 * @return True if \c yr is a leap year, otherwise false.
 
 */
 
/* static */ bool TimerGameCalendar::IsLeapYear(TimerGameCalendar::Year yr)
 
{
 
	return static_cast<int32_t>(yr) % 4 == 0 && (static_cast<int32_t>(yr) % 100 != 0 || static_cast<int32_t>(yr) % 400 == 0);
 
}
 

	
 
/**
 
 * Set the date.
 
 * @param date  New date
 
 * @param fract The number of ticks that have passed on this date.
 
 */
 
/* static */ void TimerGameCalendar::SetDate(TimerGameCalendar::Date date, TimerGameCalendar::DateFract fract)
 
{
 
	assert(fract < Ticks::DAY_TICKS);
 

	
 
	YearMonthDay ymd;
 
	TimerGameCalendar::YearMonthDay ymd;
 

	
 
	TimerGameCalendar::date = date;
 
	TimerGameCalendar::date_fract = fract;
 
	TimerGameCalendar::ConvertDateToYMD(date, &ymd);
 
	TimerGameCalendar::year = ymd.year;
 
	TimerGameCalendar::month = ymd.month;
 
}
 

	
 
template<>
 
void IntervalTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
 
{
 
	if (trigger == this->period.trigger) {
 
		this->callback(1);
 
	}
 
}
 

	
 
template<>
 
void TimeoutTimer<TimerGameCalendar>::Elapsed(TimerGameCalendar::TElapsed trigger)
 
{
 
	if (this->fired) return;
 

	
 
	if (trigger == this->period.trigger) {
 
		this->callback();
 
		this->fired = true;
 
@@ -219,51 +219,51 @@ void TimerManager<TimerGameCalendar>::El
 
		for (auto timer : timers) {
 
			timer->Elapsed(TimerGameCalendar::WEEK);
 
		}
 
	}
 

	
 
	if (new_month) {
 
		for (auto timer : timers) {
 
			timer->Elapsed(TimerGameCalendar::MONTH);
 
		}
 

	
 
		if ((TimerGameCalendar::month % 3) == 0) {
 
			for (auto timer : timers) {
 
				timer->Elapsed(TimerGameCalendar::QUARTER);
 
			}
 
		}
 
	}
 

	
 
	if (new_year) {
 
		for (auto timer : timers) {
 
			timer->Elapsed(TimerGameCalendar::YEAR);
 
		}
 
	}
 

	
 
	/* check if we reached the maximum year, decrement dates by a year */
 
	if (TimerGameCalendar::year == MAX_YEAR + 1) {
 
	if (TimerGameCalendar::year == CalendarTime::MAX_YEAR + 1) {
 
		int days_this_year;
 

	
 
		TimerGameCalendar::year--;
 
		days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
 
		days_this_year = TimerGameCalendar::IsLeapYear(TimerGameCalendar::year) ? CalendarTime::DAYS_IN_LEAP_YEAR : CalendarTime::DAYS_IN_YEAR;
 
		TimerGameCalendar::date -= days_this_year;
 
		for (Vehicle *v : Vehicle::Iterate()) v->ShiftDates(-days_this_year);
 
		for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(-days_this_year);
 
	}
 
}
 

	
 
#ifdef WITH_ASSERT
 
template<>
 
void TimerManager<TimerGameCalendar>::Validate(TimerGameCalendar::TPeriod period)
 
{
 
	if (period.priority == TimerGameCalendar::Priority::NONE) return;
 

	
 
	/* Validate we didn't make a developer error and scheduled more than one
 
	 * entry on the same priority/trigger. There can only be one timer on
 
	 * a specific trigger/priority, to ensure we are deterministic. */
 
	for (const auto &timer : TimerManager<TimerGameCalendar>::GetTimers()) {
 
		if (timer->period.trigger != period.trigger) continue;
 

	
 
		assert(timer->period.priority != period.priority);
 
	}
 
}
 
#endif /* WITH_ASSERT */

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)