1
0
Fork 0

Compare commits

...

7 Commits

Author SHA1 Message Date
Peter Nelson 5d2ed80c95 Fix: Changing group parent did not properly update partially-default liveries. 2023-12-28 23:16:19 +00:00
Peter Nelson bfb4254226 Fix: Changing default livery did not propagate to group liveries.
#11614 attempted to address this but did not handle 2CC properly, and changes to the default livery were not handled.
2023-12-28 23:16:19 +00:00
Jonathan G Rennison 3b18877b87
Fix #11629: AirportGetNearestTown for rotated airports (#11631)
Add rotation parameter to AirportGetNearestTown
Add wrapper for existing stations
Remove unnecessary iterator cloning
2023-12-28 21:43:05 +00:00
Peter Nelson 33ff64ef74
Codechange: Simplify ConvertDateToYMD by returning YearMonthDay instead of outputting to a pointer. (#11637) 2023-12-28 21:34:08 +00:00
Peter Nelson bd3b28551e Codechange: Replace reliability magic numbers with constants.
These are derived as a percentage of UINT16_MAX.
2023-12-28 21:26:24 +00:00
Peter Nelson 7b2c143df0 Fix: Prevent underflow if engine base life is less than 8 years. 2023-12-28 21:26:24 +00:00
translators ead5ad119c Update: Translations from eints
english (au): 11 changes by krysclarke
danish: 9 changes by bscargo
portuguese (brazilian): 10 changes by pasantoro
2023-12-28 18:38:31 +00:00
28 changed files with 172 additions and 113 deletions

View File

@ -920,8 +920,7 @@ void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
{
const Engine *e = Engine::Get(engine_number);
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(e->intro_date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
bool refittable = IsArticulatedVehicleRefittable(engine_number);
bool articulated_cargo = false;

View File

@ -104,8 +104,7 @@ static int32_t ClickChangeDateCheat(int32_t new_value, int32_t)
auto new_year = Clamp(TimerGameCalendar::Year(new_value), CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
if (new_year == TimerGameCalendar::year) return TimerGameCalendar::year.base();
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
TimerGameCalendar::Date new_date = TimerGameCalendar::ConvertYMDToDate(new_year, ymd.month, ymd.day);
/* Shift cached dates before we change the date. */

View File

@ -949,6 +949,20 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf
return CommandCost();
}
/**
* Update liveries for a company. This is called when the LS_DEFAULT scheme is changed, to update schemes with colours
* set to default.
* @param c Company to update.
*/
void UpdateCompanyLiveries(Company *c)
{
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
}
UpdateCompanyGroupLiveries(c);
}
/**
* Change the company's company-colour
* @param flags operation to perform
@ -982,9 +996,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool p
/* If setting the first colour of the default scheme, adjust the
* original and cached company colours too. */
if (scheme == LS_DEFAULT) {
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = colour;
}
UpdateCompanyLiveries(c);
_company_colours[_current_company] = colour;
c->colour = colour;
CompanyAdminUpdate(c);
@ -995,9 +1007,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool p
c->livery[scheme].colour2 = colour;
if (scheme == LS_DEFAULT) {
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour;
}
UpdateCompanyGroupLiveries(c);
}
}

View File

@ -24,6 +24,7 @@ void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover);
void CompanyAdminUpdate(const Company *company);
void CompanyAdminBankrupt(CompanyID company_id);
void UpdateLandscapingLimits();
void UpdateCompanyLiveries(Company *c);
bool CheckCompanyHasMoney(CommandCost &cost);
void SubtractMoneyFromCompany(const CommandCost& cost);

View File

@ -907,18 +907,18 @@ public:
int y = ir.top;
/* Helper function to draw livery info. */
auto draw_livery = [&](StringID str, const Livery &liv, bool sel, bool def, int indent) {
auto draw_livery = [&](StringID str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
/* Livery Label. */
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, sel ? TC_WHITE : TC_BLACK);
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
/* Text below the first dropdown. */
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (def || HasBit(liv.in_use, 0)) ? STR_COLOUR_DARK_BLUE + liv.colour1 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
/* Text below the second dropdown. */
if (sec.right > sec.left) { // Second dropdown has non-zero size.
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (def || HasBit(liv.in_use, 1)) ? STR_COLOUR_DARK_BLUE + liv.colour2 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
}
y += this->line_height;
@ -938,9 +938,8 @@ public:
uint max = static_cast<uint>(std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->groups.size()));
for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
const Group *g = this->groups[i];
const bool livery_set = HasBit(g->livery.in_use, 0);
SetDParam(0, g->index);
draw_livery(STR_GROUP_NAME, livery_set ? g->livery : c->livery[LS_DEFAULT], this->sel == g->index, livery_set, this->indents[i] * WidgetDimensions::scaled.hsep_indent);
draw_livery(STR_GROUP_NAME, g->livery, this->sel == g->index, false, this->indents[i] * WidgetDimensions::scaled.hsep_indent);
}
if (this->vscroll->GetCount() == 0) {

View File

@ -1442,8 +1442,7 @@ DEF_CONSOLE_CMD(ConGetDate)
return true;
}
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
IConsolePrint(CC_DEFAULT, "Date: {:04d}-{:02d}-{:02d}", ymd.year, ymd.month + 1, ymd.day);
return true;
}

View File

@ -57,8 +57,7 @@ static void SurveyRecentNews(nlohmann::json &json)
int i = 0;
for (NewsItem *news = _latest_news; i < 32 && news != nullptr; news = news->prev, i++) {
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(news->date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(news->date);
json.push_back(fmt::format("({}-{:02}-{:02}) StringID: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}",
ymd.year, ymd.month + 1, ymd.day, news->string_id, news->type,
news->reftype1, news->ref1, news->reftype2, news->ref2));

View File

@ -51,7 +51,7 @@ struct SetDateWindow : Window {
this->InitNested(window_number);
if (initial_date == 0) initial_date = TimerGameCalendar::date;
TimerGameCalendar::ConvertDateToYMD(initial_date, &this->date);
this->date = TimerGameCalendar::ConvertDateToYMD(initial_date);
this->date.year = Clamp(this->date.year, min_year, max_year);
}

View File

@ -663,8 +663,7 @@ void SetYearEngineAgingStops()
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 + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
_year_engine_aging_stops = std::max(_year_engine_aging_stops, ymd.year);
}
@ -717,14 +716,25 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
e->type ^
e->GetGRFID());
r = Random();
e->reliability_start = GB(r, 16, 14) + 0x7AE0;
e->reliability_max = GB(r, 0, 14) + 0xBFFF;
/* Base reliability defined as a percentage of UINT16_MAX. */
const uint16_t RELIABILITY_START = UINT16_MAX * 48 / 100;
const uint16_t RELIABILITY_MAX = UINT16_MAX * 75 / 100;
const uint16_t RELIABILITY_FINAL = UINT16_MAX * 25 / 100;
static_assert(RELIABILITY_START == 0x7AE0);
static_assert(RELIABILITY_MAX == 0xBFFF);
static_assert(RELIABILITY_FINAL == 0x3FFF);
r = Random();
e->reliability_final = GB(r, 16, 14) + 0x3FFF;
/* 14 bits gives a value between 0 and 16383, which is up to an additional 25%p reliability on top of the base reliability. */
e->reliability_start = GB(r, 16, 14) + RELIABILITY_START;
e->reliability_max = GB(r, 0, 14) + RELIABILITY_MAX;
r = Random();
e->reliability_final = GB(r, 16, 14) + RELIABILITY_FINAL;
e->duration_phase_1 = GB(r, 0, 5) + 7;
e->duration_phase_2 = GB(r, 5, 4) + ei->base_life.base() * 12 - 96;
e->duration_phase_2 = std::max(0, int(GB(r, 5, 4)) + ei->base_life.base() * 12 - 96);
e->duration_phase_3 = GB(r, 9, 7) + 120;
RestoreRandomSeeds(saved_seeds);

View File

@ -112,5 +112,6 @@ void SetTrainGroupID(Train *v, GroupID grp);
void UpdateTrainGroupID(Train *v);
void RemoveAllGroupsForCompany(const CompanyID company);
bool GroupIsInGroup(GroupID search, GroupID group);
void UpdateCompanyGroupLiveries(const Company *c);
#endif /* GROUP_H */

View File

@ -275,17 +275,20 @@ const Livery *GetParentLivery(const Group *g)
/**
* Propagate a livery change to a group's children.
* @param g Group.
* Propagate a livery change to a group's children, and optionally update cached vehicle colourmaps.
* @param g Group to propagate colours to children.
* @param reset_cache Reset colourmap of vehicles in this group.
*/
void PropagateChildLivery(const Group *g)
static void PropagateChildLivery(const Group *g, bool reset_cache)
{
/* Company colour data is indirectly cached. */
for (Vehicle *v : Vehicle::Iterate()) {
if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) {
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
if (reset_cache) {
/* Company colour data is indirectly cached. */
for (Vehicle *v : Vehicle::Iterate()) {
if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) {
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
}
}
}
}
@ -294,11 +297,26 @@ void PropagateChildLivery(const Group *g)
if (cg->parent == g->index) {
if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
PropagateChildLivery(cg);
PropagateChildLivery(cg, reset_cache);
}
}
}
/**
* Update group liveries for a company. This is called when the LS_DEFAULT scheme is changed, to update groups with
* colours set to default.
* @param c Company to update.
*/
void UpdateCompanyGroupLiveries(const Company *c)
{
for (Group *g : Group::Iterate()) {
if (g->owner == c->index && g->parent == INVALID_GROUP) {
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
PropagateChildLivery(g, false);
}
}
}
Group::Group(Owner owner)
{
@ -448,12 +466,13 @@ CommandCost CmdAlterGroup(DoCommandFlag flags, AlterGroupMode mode, GroupID grou
g->parent = (pg == nullptr) ? INVALID_GROUP : pg->index;
GroupStatistics::UpdateAutoreplace(g->owner);
if (g->livery.in_use == 0) {
if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) {
/* Update livery with new parent's colours if either colour is default. */
const Livery *livery = GetParentLivery(g);
g->livery.colour1 = livery->colour1;
g->livery.colour2 = livery->colour2;
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
PropagateChildLivery(g);
PropagateChildLivery(g, true);
MarkWholeScreenDirty();
}
}
@ -661,7 +680,7 @@ CommandCost CmdSetGroupLivery(DoCommandFlag flags, GroupID group_id, bool primar
g->livery.colour2 = colour;
}
PropagateChildLivery(g);
PropagateChildLivery(g, true);
MarkWholeScreenDirty();
}

View File

@ -609,8 +609,7 @@ byte GetSnowLine()
{
if (_snow_line == nullptr) return _settings_game.game_creation.snow_line_height;
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
return _snow_line->table[ymd.month][ymd.day];
}

View File

@ -2197,9 +2197,17 @@ STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Exibe es
STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Exibir os esquemas de cor de automóveis
STR_LIVERY_SHIP_TOOLTIP :{BLACK}Exibir esquemas de cor de embarcação
STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Exibir esquemas de cor de aviões
STR_LIVERY_TRAIN_GROUP_TOOLTIP :{BLACK}Exibir cores de grupos de trens
STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP :{BLACK}Exibir cores dos grupos de veículos
STR_LIVERY_SHIP_GROUP_TOOLTIP :{BLACK}Exibir cores de grupos de embarcações
STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP :{BLACK}Exibir cores dos grupos de aeronaves
STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Escolha a cor principal para o esquema selecionado. Ctrl+Clique seleciona essa cor para todos os esquemas
STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Escolha a cor secundária para o esquema selecionado. Ctrl+Clique seleciona essa cor para todos os esquemas
STR_LIVERY_PANEL_TOOLTIP :{BLACK}Selecionar um esquema de cores para mudar, ou múltiplos esquemas com CTRL+clique. Marque a opção para utilizar o esquema
STR_LIVERY_TRAIN_GROUP_EMPTY :Não há grupos de trens configurados
STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY :Não há grupos de veículos configurados
STR_LIVERY_SHIP_GROUP_EMPTY :Não há grupos de embarcações configurados
STR_LIVERY_AIRCRAFT_GROUP_EMPTY :Não há grupos de aeronaves configurados
###length 23
STR_LIVERY_DEFAULT :Cores padrão
@ -4654,9 +4662,9 @@ STR_AI_DEBUG_MATCH_CASE :{BLACK}Correspo
STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Alternar correspondencia de "case" quando comparar mensagens de resgisto da IA contra a sequencia de falhas
STR_AI_DEBUG_CONTINUE :{BLACK}Continuar
STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Despausar e continuar o AI
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Ver a depuração produzida desta IA
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Ver saída de depuração desta IA
STR_AI_GAME_SCRIPT :{BLACK}Game Script
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Checando o log do Game Script
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Verifique o registo do Script de jogo
STR_ERROR_AI_NO_AI_FOUND :Nenhuma IA adequada encontrada para carregar.{} Esta IA é falsa e não irá fazer nada.{} Você pode pode baixar várias IA através do sistema de 'Conteúdo Online'
STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Um dos scripts em execução travou. Favor relatar isto ao autor do script com uma captura de tela da Janela de Depuração da I.A./Script do jogo

View File

@ -2194,12 +2194,19 @@ STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Vis farv
STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Vis farveskemaer for køretøjer
STR_LIVERY_SHIP_TOOLTIP :{BLACK}Vis farveskemaer for skibe
STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Vis farveskemaer for fly
STR_LIVERY_TRAIN_GROUP_TOOLTIP :{BLACK}Vis farver på toggrupper
STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP :{BLACK}Vis farver på vejkøretøjsgrupper
STR_LIVERY_SHIP_GROUP_TOOLTIP :{BLACK}Vis farver på skibsgrupper
STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP :{BLACK}Vis farverne på flygrupper
STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Vælg den primære farve for det valgte farveskema. Ctrl+Click vil sætte denne farve for alle farveskemaer
STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Vælg den sekundære farve for det valgte farveskema. Ctrl+Click vil sætte denne farve for alle farveskemaer
STR_LIVERY_PANEL_TOOLTIP :{BLACK}Vælg et farveskema, som skal ændres, eller flere farveskemaer vha. CTRL+klik. Klik på boksen for at slå brug af farveskemaet til/fra
STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY :Der er ikke oprettet grupper af vejkøretøjer
STR_LIVERY_SHIP_GROUP_EMPTY :Der er ikke oprettet skibsgrupper
STR_LIVERY_AIRCRAFT_GROUP_EMPTY :Der er ikke oprettet flygrupper
###length 23
STR_LIVERY_DEFAULT :Standardfarver
STR_LIVERY_DEFAULT :Standard Livery
STR_LIVERY_STEAM :Damplokomotiv
STR_LIVERY_DIESEL :Diesellokomotiv
STR_LIVERY_ELECTRIC :Elektrisk lokomotiv
@ -4651,7 +4658,7 @@ STR_AI_DEBUG_MATCH_CASE :{BLACK}Match st
STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Vis matchende stort/lille bogstav ved sammenligning af AI log beskeder messages mod teksten
STR_AI_DEBUG_CONTINUE :{BLACK}Fortsæt
STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Sæt spillet i gang, og start den kunstige intelligens igen
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Se debug output for denne AI
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Se fejlretningsoutput af denne AI. Ctrl-klik for at åbne i et nyt vindue
STR_AI_GAME_SCRIPT :{BLACK}Spil Script
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Tjek SpilScript-loggen

View File

@ -2196,12 +2196,20 @@ STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Show tra
STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Show road vehicle colour schemes
STR_LIVERY_SHIP_TOOLTIP :{BLACK}Show ship colour schemes
STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Show aircraft colour schemes
STR_LIVERY_TRAIN_GROUP_TOOLTIP :{BLACK}Show colours of train groups
STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP :{BLACK}Show colours of road vehicle groups
STR_LIVERY_SHIP_GROUP_TOOLTIP :{BLACK}Show colours of ship groups
STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP :{BLACK}Show colours of aircraft groups
STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Choose the primary colour for the selected scheme. Ctrl+Click will set this colour for every scheme
STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Choose the secondary colour for the selected scheme. Ctrl+Click will set this colour for every scheme
STR_LIVERY_PANEL_TOOLTIP :{BLACK}Select a colour scheme to change, or multiple schemes with Ctrl+Click. Click on the box to toggle use of the scheme
STR_LIVERY_TRAIN_GROUP_EMPTY :No train groups are set up
STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY :No road vehicle groups are set up
STR_LIVERY_SHIP_GROUP_EMPTY :No ship groups are set up
STR_LIVERY_AIRCRAFT_GROUP_EMPTY :No aircraft groups are set up
###length 23
STR_LIVERY_DEFAULT :Standard Livery
STR_LIVERY_DEFAULT :Default Livery
STR_LIVERY_STEAM :Steam Engine
STR_LIVERY_DIESEL :Diesel Engine
STR_LIVERY_ELECTRIC :Electric Engine
@ -4653,9 +4661,9 @@ STR_AI_DEBUG_MATCH_CASE :{BLACK}Match ca
STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing AI log messages against the break string
STR_AI_DEBUG_CONTINUE :{BLACK}Continue
STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Unpause and continue the AI
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}View debug output of this AI
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}View debug output of this AI. Ctrl-Click to open in a new window
STR_AI_GAME_SCRIPT :{BLACK}Game Script
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check the Game Script log
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check the Game Script log. Ctrl-Click to open in a new window
STR_ERROR_AI_NO_AI_FOUND :No suitable AI found to load.{}This AI is a dummy AI and won't do anything.{}You can download several AIs via the 'Online Content' system
STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}One of the running scripts crashed. Please report this to the script author with a screenshot of the AI/Game Script Debug Window

View File

@ -381,8 +381,7 @@ protected:
if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_DATE); nwid->current_x != 0) {
/* current date */
Rect date = nwid->GetCurrentRect();
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date);
SetDParam(0, ymd.year);
DrawString(date.left, date.right, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
}
@ -390,9 +389,8 @@ protected:
if (const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(WID_NG_YEARS); nwid->current_x != 0) {
/* number of years the game is running */
Rect years = nwid->GetCurrentRect();
TimerGameCalendar::YearMonthDay ymd_cur, ymd_start;
TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date, &ymd_cur);
TimerGameCalendar::ConvertDateToYMD(cur_item->info.start_date, &ymd_start);
TimerGameCalendar::YearMonthDay ymd_cur = TimerGameCalendar::ConvertDateToYMD(cur_item->info.game_date);
TimerGameCalendar::YearMonthDay ymd_start = TimerGameCalendar::ConvertDateToYMD(cur_item->info.start_date);
SetDParam(0, ymd_cur.year - ymd_start.year);
DrawString(years.left, years.right, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER);
}

View File

@ -6520,8 +6520,7 @@ bool GetGlobalVariable(byte param, uint32_t *value, const GRFFile *grffile)
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::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
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) | (TimerGameCalendar::date - start_of_year).base() << 16;
return true;

View File

@ -3262,6 +3262,10 @@ bool AfterLoadGame()
}
}
for (Company *c : Company::Iterate()) {
UpdateCompanyLiveries(c);
}
AfterLoadLabelMaps();
AfterLoadCompanyStats();
AfterLoadStoryBook();

View File

@ -844,8 +844,7 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
if (i->type > 0x06) i->type++; // Printing Works were added
if (i->type == 0x0A) i->type = 0x12; // Iron Ore Mine has different ID
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
i->last_prod_year = ymd.year;
i->random_colour = RemapTTOColour(i->random_colour);

View File

@ -137,9 +137,8 @@
if (!as->IsWithinMapBounds(0, tile)) return -1;
if (_settings_game.economy.station_noise_level) {
AirportTileTableIterator it(as->table[0], tile);
uint dist;
AirportGetNearestTown(as, tile, it, dist);
AirportGetNearestTown(as, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist);
return GetAirportNoiseLevelForDistance(as, dist);
}
@ -155,7 +154,7 @@
if (!as->IsWithinMapBounds(0, tile)) return INVALID_TOWN;
uint dist;
return AirportGetNearestTown(as, tile, AirportTileTableIterator(as->table[0], tile), dist)->index;
return AirportGetNearestTown(as, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist)->index;
}
/* static */ SQInteger ScriptAirport::GetMaintenanceCostFactor(AirportType type)

View File

@ -29,8 +29,7 @@
{
if (date < 0) return DATE_INVALID;
::TimerGameCalendar::YearMonthDay ymd;
::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.year.base();
}
@ -38,8 +37,7 @@
{
if (date < 0) return DATE_INVALID;
::TimerGameCalendar::YearMonthDay ymd;
::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.month + 1;
}
@ -47,8 +45,7 @@
{
if (date < 0) return DATE_INVALID;
::TimerGameCalendar::YearMonthDay ymd;
::TimerGameCalendar::ConvertDateToYMD(date, &ymd);
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.day;
}

View File

@ -2303,28 +2303,32 @@ uint8_t GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance)
* Finds the town nearest to given airport. Based on minimal manhattan distance to any airport's tile.
* If two towns have the same distance, town with lower index is returned.
* @param as airport's description
* @param rotation airport's rotation
* @param tile origin tile (top corner of the airport)
* @param it An iterator over all airport tiles
* @param it An iterator over all airport tiles (consumed)
* @param[out] mindist Minimum distance to town
* @return nearest town to airport
*/
Town *AirportGetNearestTown(const AirportSpec *as, TileIndex tile, const TileIterator &it, uint &mindist)
Town *AirportGetNearestTown(const AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist)
{
assert(Town::GetNumItems() > 0);
Town *nearest = nullptr;
auto width = as->size_x;
auto height = as->size_y;
if (rotation == DIR_E || rotation == DIR_W) std::swap(width, height);
uint perimeter_min_x = TileX(tile);
uint perimeter_min_y = TileY(tile);
uint perimeter_max_x = perimeter_min_x + as->size_x - 1;
uint perimeter_max_y = perimeter_min_y + as->size_y - 1;
uint perimeter_max_x = perimeter_min_x + width - 1;
uint perimeter_max_y = perimeter_min_y + height - 1;
mindist = UINT_MAX - 1; // prevent overflow
std::unique_ptr<TileIterator> copy(it.Clone());
for (TileIndex cur_tile = *copy; cur_tile != INVALID_TILE; cur_tile = ++*copy) {
assert(IsInsideBS(TileX(cur_tile), perimeter_min_x, as->size_x));
assert(IsInsideBS(TileY(cur_tile), perimeter_min_y, as->size_y));
for (TileIndex cur_tile = *it; cur_tile != INVALID_TILE; cur_tile = ++it) {
assert(IsInsideBS(TileX(cur_tile), perimeter_min_x, width));
assert(IsInsideBS(TileY(cur_tile), perimeter_min_y, height));
if (TileX(cur_tile) == perimeter_min_x || TileX(cur_tile) == perimeter_max_x || TileY(cur_tile) == perimeter_min_y || TileY(cur_tile) == perimeter_max_y) {
Town *t = CalcClosestTownFromTile(cur_tile, mindist + 1);
if (t == nullptr) continue;
@ -2341,6 +2345,18 @@ Town *AirportGetNearestTown(const AirportSpec *as, TileIndex tile, const TileIte
return nearest;
}
/**
* Finds the town nearest to given existing airport. Based on minimal manhattan distance to any airport's tile.
* If two towns have the same distance, town with lower index is returned.
* @param station existing station with airport
* @param[out] mindist Minimum distance to town
* @return nearest town to airport
*/
static Town *AirportGetNearestTown(const Station *st, uint &mindist)
{
return AirportGetNearestTown(st->airport.GetSpec(), st->airport.rotation, st->airport.tile, AirportTileIterator(st), mindist);
}
/** Recalculate the noise generated by the airports of each town */
void UpdateAirportsNoise()
@ -2349,11 +2365,9 @@ void UpdateAirportsNoise()
for (const Station *st : Station::Iterate()) {
if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) {
const AirportSpec *as = st->airport.GetSpec();
AirportTileIterator it(st);
uint dist;
Town *nearest = AirportGetNearestTown(as, st->airport.tile, it, dist);
nearest->noise_reached += GetAirportNoiseLevelForDistance(as, dist);
Town *nearest = AirportGetNearestTown(st, dist);
nearest->noise_reached += GetAirportNoiseLevelForDistance(st->airport.GetSpec(), dist);
}
}
}
@ -2402,7 +2416,7 @@ CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, byte airport_ty
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
uint dist;
Town *nearest = AirportGetNearestTown(as, tile, tile_iter, dist);
Town *nearest = AirportGetNearestTown(as, rotation, tile, std::move(tile_iter), dist);
uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist);
/* Check if local auth would allow a new airport */
@ -2524,14 +2538,12 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
CloseWindowById(WC_VEHICLE_DEPOT, tile_cur);
}
const AirportSpec *as = st->airport.GetSpec();
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
* And as for construction, always remove it, even if the setting is not set, in order to avoid the
* need of recalculation */
AirportTileIterator it(st);
uint dist;
Town *nearest = AirportGetNearestTown(as, st->airport.tile, it, dist);
nearest->noise_reached -= GetAirportNoiseLevelForDistance(as, dist);
Town *nearest = AirportGetNearestTown(st, dist);
nearest->noise_reached -= GetAirportNoiseLevelForDistance(st->airport.GetSpec(), dist);
if (_settings_game.economy.station_noise_level) {
SetWindowDirty(WC_TOWN_VIEW, nearest->index);

View File

@ -16,7 +16,7 @@
enum StationClassID : byte;
enum RoadStopClassID : byte;
extern Town *AirportGetNearestTown(const struct AirportSpec *as, TileIndex tile, const TileIterator &it, uint &mindist);
extern Town *AirportGetNearestTown(const struct AirportSpec *as, Direction rotation, TileIndex tile, TileIterator &&it, uint &mindist);
extern uint8_t GetAirportNoiseLevelForDistance(const struct AirportSpec *as, uint distance);
CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, byte airport_type, byte layout, StationID station_to_join, bool allow_adjacent);

View File

@ -483,8 +483,7 @@ static void FormatBytes(StringBuilder &builder, int64_t number)
static void FormatYmdString(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
{
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
auto tmp_params = MakeParameters(ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year);
FormatString(builder, GetStringPtr(STR_FORMAT_DATE_LONG), tmp_params, case_index);
@ -492,8 +491,7 @@ static void FormatYmdString(StringBuilder &builder, TimerGameCalendar::Date date
static void FormatMonthAndYear(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
{
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
auto tmp_params = MakeParameters(STR_MONTH_JAN + ymd.month, ymd.year);
FormatString(builder, GetStringPtr(STR_FORMAT_DATE_SHORT), tmp_params, case_index);
@ -501,8 +499,7 @@ static void FormatMonthAndYear(StringBuilder &builder, TimerGameCalendar::Date d
static void FormatTinyOrISODate(StringBuilder &builder, TimerGameCalendar::Date date, StringID str)
{
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
/* Day and month are zero-padded with ZEROFILL_NUM, hence the two 2s. */
auto tmp_params = MakeParameters(ymd.day, 2, ymd.month + 1, 2, ymd.year);

View File

@ -142,8 +142,7 @@ struct SubsidyListWindow : Window {
{
if (widget != WID_SUL_PANEL) return;
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);

View File

@ -311,8 +311,7 @@ void SurveyTimers(nlohmann::json &survey)
survey["ticks"] = TimerGameTick::counter;
survey["seconds"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - _switch_mode_time).count();
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", ymd.year, ymd.month + 1, ymd.day, TimerGameCalendar::date_fract);
}

View File

@ -66,9 +66,9 @@ static const uint16_t _accum_days_for_month[] = {
/**
* 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
* @returns YearMonthDay representation of the Date.
*/
/* static */ void TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date, TimerGameCalendar::YearMonthDay *ymd)
/* static */ TimerGameCalendar::YearMonthDay TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::Date date)
{
/* Year determination in multiple steps to account for leap
* years. First do the large steps, then the smaller ones.
@ -77,7 +77,6 @@ static const uint16_t _accum_days_for_month[] = {
/* There are 97 leap years in 400 years */
TimerGameCalendar::Year yr = 400 * (date.base() / (CalendarTime::DAYS_IN_YEAR * 400 + 97));
int rem = date.base() % (CalendarTime::DAYS_IN_YEAR * 400 + 97);
uint16_t x;
if (rem >= CalendarTime::DAYS_IN_YEAR * 100 + 25) {
/* There are 25 leap years in the first 100 years after
@ -110,11 +109,13 @@ static const uint16_t _accum_days_for_month[] = {
/* Skip the 29th of February in non-leap years */
if (!TimerGameCalendar::IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
ymd->year = yr;
uint16_t x = _month_date_from_year_day[rem];
x = _month_date_from_year_day[rem];
ymd->month = x >> 5;
ymd->day = x & 0x1F;
YearMonthDay ymd;
ymd.year = yr;
ymd.month = x >> 5;
ymd.day = x & 0x1F;
return ymd;
}
/**
@ -153,11 +154,9 @@ static const uint16_t _accum_days_for_month[] = {
{
assert(fract < Ticks::DAY_TICKS);
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::date = date;
TimerGameCalendar::date_fract = fract;
TimerGameCalendar::ConvertDateToYMD(date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
TimerGameCalendar::year = ymd.year;
TimerGameCalendar::month = ymd.month;
}
@ -195,8 +194,7 @@ void TimerManager<TimerGameCalendar>::Elapsed([[maybe_unused]] TimerGameCalendar
/* increase day counter */
TimerGameCalendar::date++;
TimerGameCalendar::YearMonthDay ymd;
TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date, &ymd);
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
/* check if we entered a new month? */
bool new_month = ymd.month != TimerGameCalendar::month;

View File

@ -101,7 +101,7 @@ public:
};
static bool IsLeapYear(Year yr);
static void ConvertDateToYMD(Date date, YearMonthDay * ymd);
static YearMonthDay ConvertDateToYMD(Date date);
static Date ConvertYMDToDate(Year year, Month month, Day day);
static void SetDate(Date date, DateFract fract);