From d751924e12174a8eea44897c9bae0f6a01af1673 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Sun, 12 Jan 2025 09:08:03 -0500 Subject: [PATCH 01/25] introduce advanced tax & wage contribution logic --- src/city/sentiment.c | 39 ++++++++++++++++++++++++++++++++++- src/core/config.h | 1 + src/translation/english.c | 1 + src/translation/french.c | 1 + src/translation/german.c | 3 ++- src/translation/greek.c | 1 + src/translation/italian.c | 1 + src/translation/korean.c | 1 + src/translation/polish.c | 1 + src/translation/portuguese.c | 1 + src/translation/russian.c | 1 + src/translation/spanish.c | 1 + src/translation/swedish.c | 1 + src/translation/translation.h | 1 + src/window/config.c | 1 + 15 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 16645c86ef..d5bc23b5c2 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -168,8 +168,30 @@ static int get_games_bonus(void) static int get_wage_sentiment_modifier(void) { + const int wage_interval = 8; int wage_differential = city_data.labor.wages - city_data.labor.wages_rome; - return wage_differential * (wage_differential > 0 ? WAGE_POSITIVE_MODIFIER : WAGE_NEGATIVE_MODIFIER); + if (wage_differential > wage_interval && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + // Precomputed wage sentiment contributions by intervals. Each next interval gives twice less + // contribution in compare to previous, making it inefficient to set wages much higher than Rome. + // When wages differential is more than 32 percent points, it stops contributing to sentiment. + const int contribution_div[4] = { 1, 2, 4, 8 }; // Divisors for the remainder + const int contribution[4] = { 8, 12, 14, 15 }; // Precomputed results for full wage intervals + const int max_interval_idx = sizeof(contribution) / sizeof(contribution[0]); + + // Determine the interval index and remainder contribution + int interval_idx = wage_differential / wage_interval; + if (interval_idx >= max_interval_idx) { + // Stop contributing if wage diff value is 32 or higher + wage_differential = contribution[max_interval_idx - 1] * WAGE_POSITIVE_MODIFIER; + } else { + // For better int precision, we multiply the reminder by wage modifier before division + int remainder = (wage_differential % wage_interval) * WAGE_POSITIVE_MODIFIER / contribution_div[interval_idx]; + wage_differential = contribution[interval_idx - 1] * WAGE_POSITIVE_MODIFIER + remainder; + } + } else { + wage_differential *= (wage_differential > 0 ? WAGE_POSITIVE_MODIFIER : WAGE_NEGATIVE_MODIFIER); + } + return wage_differential; } static int get_unemployment_sentiment_modifier(void) @@ -186,6 +208,21 @@ static int get_sentiment_modifier_for_tax_rate(int tax) int base_tax = difficulty_base_tax_rate(); int tax_differential = base_tax - tax; tax_differential *= tax_differential < 0 ? (MAX_TAX_MULTIPLIER - base_tax) : (base_tax / 2); + if (tax_differential < 0 && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + // Extra sentiment punishment applies when player sets higher taxes. + // Multiplier is a power of 2, where exponent is doubled after tax difference + // reaches next interval, which is half of base tax rate. + // Example: + // In very hard mode the base tax rate is 6%. Player sets current tax level to 15%. + // Tax difference is 9%. The interval is 6% / 2 = 3%. It means that for every next 3% of tax + // higher than 6% the tax sentiment multiplier will be doubled. This gives us a tax differential + // value (6% - 15%) * (12% - 6%) * 2^(9% / 3%) = -9% * 6% * 8 = -432 (original value was -54). + int interval = calc_bound(base_tax / 2, 2, 8); + int tax_diff = tax - base_tax; + if (tax_diff >= interval) { + tax_differential *= 2 << calc_bound(tax_diff / interval - 1, 0, 8); + } + } return tax_differential; } diff --git a/src/core/config.h b/src/core/config.h index 184f78c0d2..950a5abca4 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -62,6 +62,7 @@ typedef enum { CONFIG_GP_CH_YEARLY_AUTOSAVE, CONFIG_GP_CH_AUTO_KILL_ANIMALS, CONFIG_GP_CH_GATES_DEFAULT_TO_PASS_ALL_WALKERS, + CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, CONFIG_UI_SHOW_SPEEDRUN_INFO, CONFIG_UI_SHOW_DESIRABILITY_RANGE, CONFIG_MAX_ENTRIES diff --git a/src/translation/english.c b/src/translation/english.c index bf95ea8376..366fe74edb 100644 --- a/src/translation/english.c +++ b/src/translation/english.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Draw cloud shadows"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Ask for confirmation when overwriting a file"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Non-military gates default to allowing all walkers"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Advanced tax & wage sentiment contribution logic"}, {TR_HOTKEY_TITLE, "Augustus hotkey configuration"}, {TR_HOTKEY_LABEL, "Hotkey"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternative"}, diff --git a/src/translation/french.c b/src/translation/french.c index d1d9f29ef6..0764b8a304 100644 --- a/src/translation/french.c +++ b/src/translation/french.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Simuler l'ombre des nuages"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Demander confirmation pour écraser un fichier"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Les arches non-militaires autorisent par défaut tous les marcheurs"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Logique avancée de contribution au sentiment fiscal et salarial"}, {TR_HOTKEY_TITLE, "Configuration raccourcis clavier"}, {TR_HOTKEY_LABEL, "Touche"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternative"}, diff --git a/src/translation/german.c b/src/translation/german.c index 3f84a30168..562015b668 100644 --- a/src/translation/german.c +++ b/src/translation/german.c @@ -119,6 +119,7 @@ static translation_string all_strings[] = { {TR_CONFIG_FULLSCREEN, "Vollbild"}, {TR_CONFIG_GAME_SPEED, "Spielgeschwindigkeit:"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Nicht-militärische Tore lassen standardmäßig alle Fußgänger zu"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Erweiterte Steuer- und Lohnstimmungsbeitragslogik"}, {TR_CONFIG_GETTING_GRANARIES_GO_OFFROAD, "Karrenschieber fordernder Silos laufen auch abseits der Straße"}, {TR_CONFIG_GLOBAL_LABOUR, "Aktiviere globalen Arbeiterpool"}, {TR_CONFIG_GODS_EFFECTS, "Götterflüche/-segnungen aktivieren"}, @@ -192,7 +193,7 @@ static translation_string all_strings[] = { "Sie können Ihre Einstellungen später im Optionsmenü ändern."}, {TR_USER_DIRECTORIES_NOT_WRITEABLE_TITLE, "Benutzerverzeichnis nicht überschreibbar."}, {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT, "Das ausgewählte Benutzerverzeichnis ist nicht überschreibbar.\n\nBitte wählen Sie ein anderes Benutzerverzeichnis."}, - {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "Das gewählte Benutzerverzeichnis ist nicht überschreibbar.\n\Sie können Ihre Spiele nicht speichern.\nBitte wählen Sie im Optionsmenü ein anderes Benutzerverzeichnis aus."}, + {TR_USER_DIRECTORIES_NOT_WRITEABLE_TEXT_DETAILED, "Das gewählte Benutzerverzeichnis ist nicht überschreibbar.\n\nSie können Ihre Spiele nicht speichern.\nBitte wählen Sie im Optionsmenü ein anderes Benutzerverzeichnis aus."}, {TR_USER_DIRECTORIES_WINDOW_TITLE, "Benutzerverzeichnis festlegen"}, {TR_USER_DIRETORIES_WINDOW_USER_PATH, "Benutzerverzeichnis:" }, {TR_USER_DIRECTORIES_USER_PATH_CHANGED_TITLE, "Benutzerpfad geändert"}, diff --git a/src/translation/greek.c b/src/translation/greek.c index d373b85237..4d94fb1169 100644 --- a/src/translation/greek.c +++ b/src/translation/greek.c @@ -113,6 +113,7 @@ static translation_string all_strings[] = { {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Ζητήστε επιβεβαίωση όταν αντικαθιστάτε ένα αρχείο"}, {TR_HOTKEY_TITLE, "Ρύθμιση πλήκτρων συντομεύσεων του Augustus"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Οι μη στρατιωτικές πύλες επιτρέπουν από προεπιλογή όλους τους περιπατητές"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Προηγμένη λογική εισφοράς φόρου και μισθολογικού κλίματος"}, {TR_HOTKEY_LABEL, "Πλήκτρα συντόμευσης"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Εναλλακτικά"}, {TR_HOTKEY_HEADER_ARROWS, "Πλήκτρα βέλους"}, diff --git a/src/translation/italian.c b/src/translation/italian.c index 0b68901461..627c0d3742 100644 --- a/src/translation/italian.c +++ b/src/translation/italian.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Disegna le ombre delle nuvole"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Chiedi conferma alla sovrascrittura di un file"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "I portali civili fanno passare tutti i passeggiatori di default"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Logica avanzata di contributo al sentimento fiscale e salariale"}, {TR_HOTKEY_TITLE, "Configura scorciatoie da tastiera Augustus"}, {TR_HOTKEY_LABEL, "Tasto"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternativa"}, diff --git a/src/translation/korean.c b/src/translation/korean.c index 9a7d1369c0..2442f9fbe8 100644 --- a/src/translation/korean.c +++ b/src/translation/korean.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "구름 그림자 표시"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "파일을 덮어쓰기 전에 물어보기"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "비군사형 문이 모든 시민이 통과 가능하도록 초기 설정됨"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "고급 세금 및 임금 감정 기여 논리"}, {TR_HOTKEY_TITLE, "Augustus 단축키 설정"}, {TR_HOTKEY_LABEL, "단축키"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "대체"}, diff --git a/src/translation/polish.c b/src/translation/polish.c index d767d9e340..dbe68fdfa4 100644 --- a/src/translation/polish.c +++ b/src/translation/polish.c @@ -1017,6 +1017,7 @@ static translation_string all_strings[] = { {TR_CONFIG_AUTO_KILL_ANIMALS, "Obywatele będą automatycznie zabijać nieszkodliwe zwierzęta"}, {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Narysuj cienie chmur"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Bramy niemilitarne domyślnie przepuszczają wszystkich obywateli"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Zaawansowana logika wliczania podatków i nastrojów płacowych"}, {TR_CONFIG_SHOW_MARKET_RANGE, "Pokaż zasięg przy budowie nowych targów"}, {TR_CONFIG_SHOW_ROAMING_PATH, "Podgląd ścieżek przebytych przez wędrujących obywateli"}, {TR_CONFIG_SHOW_WATER_STRUCTURE_RANGE_HOUSES, "Pokaż zasięg fontann i studni podczas budowy domów"}, diff --git a/src/translation/portuguese.c b/src/translation/portuguese.c index c05f1d9f55..dff8b608c6 100644 --- a/src/translation/portuguese.c +++ b/src/translation/portuguese.c @@ -1063,6 +1063,7 @@ static translation_string all_strings[] = { {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Solicitar confirmação para substituir arquivo"}, {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Desenhar sombras de nuvens"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Sincronizar portões não militares para permitir todo tipo de trabalhador"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Lógica avançada de contribuição de sentimento fiscal e salarial"}, {TR_EDITOR_CHECK_LOG_MESSAGE, "Por favor, confira augustus-log.txt no seu diretório do Augustus para detalhes."}, {TR_EDITOR_CUSTOM_MESSAGES_CLEAR, "Apagar mensagens" }, {TR_EDITOR_CUSTOM_MESSAGES_COUNT, "Total de mensagens" }, diff --git a/src/translation/russian.c b/src/translation/russian.c index 1a84a8b10e..b80a96183f 100644 --- a/src/translation/russian.c +++ b/src/translation/russian.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Показать тени облаков"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Запрашивать подтверждение при перезаписи файла"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Невоенные ворота по умолчанию пропускают всех пешеходов"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Расширенная логика подсчета влияния налогов & жалований на настроение жителей"}, {TR_HOTKEY_TITLE, "Настройки горячих клавиш Augustus"}, {TR_HOTKEY_LABEL, "Основная"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Альтернативная"}, diff --git a/src/translation/spanish.c b/src/translation/spanish.c index 7cbc9f0fae..36ac0c968b 100644 --- a/src/translation/spanish.c +++ b/src/translation/spanish.c @@ -112,6 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Dibuja sombras de nubes"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Preguntar el confirmar al sobreescribir un archivo"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Puertas no militar permite por defecto a los caminantes "}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Lógica avanzada de contribución al sentimiento salarial e impositivo"}, {TR_HOTKEY_TITLE, "Configuración de atajos de teclado de Augustus"}, {TR_HOTKEY_LABEL, "Principal"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternativo"}, diff --git a/src/translation/swedish.c b/src/translation/swedish.c index 3b21f3729a..2f3d3d798c 100644 --- a/src/translation/swedish.c +++ b/src/translation/swedish.c @@ -1004,6 +1004,7 @@ static translation_string all_strings[] = { {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Be om bekräftelse när en fil skrivs över"}, {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Visa skuggor från moln"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Icke-militära grindar förinställda att att tillåta strövande medborgare"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Avancerad skatte- och lönesentimentbidragslogik"}, {TR_FIGURE_INFO_DEPOT_DELIVER, "Levererar"}, {TR_FIGURE_INFO_DEPOT_FROM, "Från "}, {TR_FIGURE_INFO_DEPOT_RECALL, "Återkalla"}, diff --git a/src/translation/translation.h b/src/translation/translation.h index 21b37e63a8..90fefc8324 100644 --- a/src/translation/translation.h +++ b/src/translation/translation.h @@ -106,6 +106,7 @@ typedef enum { TR_CONFIG_DRAW_CLOUD_SHADOWS, TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, + TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, TR_HOTKEY_TITLE, TR_HOTKEY_LABEL, TR_HOTKEY_ALTERNATIVE_LABEL, diff --git a/src/window/config.c b/src/window/config.c index 84a8909e48..aad2d8aa4a 100644 --- a/src/window/config.c +++ b/src/window/config.c @@ -256,6 +256,7 @@ static config_widget all_widgets[CONFIG_PAGES][MAX_WIDGETS] = { {TYPE_CHECKBOX, CONFIG_GP_CH_ROAMERS_DONT_SKIP_CORNERS, TR_CONFIG_ROAMERS_DONT_SKIP_CORNERS }, {TYPE_CHECKBOX, CONFIG_GP_CH_AUTO_KILL_ANIMALS, TR_CONFIG_AUTO_KILL_ANIMALS}, {TYPE_CHECKBOX, CONFIG_GP_CH_GATES_DEFAULT_TO_PASS_ALL_WALKERS, TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS}, + {TYPE_CHECKBOX, CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION}, } }; From e8eb3f84deb4ffd35158d18e8d55e2f25c91754c Mon Sep 17 00:00:00 2001 From: ZelionD Date: Sun, 12 Jan 2025 10:46:30 -0500 Subject: [PATCH 02/25] replace & with and word --- src/translation/english.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translation/english.c b/src/translation/english.c index 366fe74edb..be725b6f0c 100644 --- a/src/translation/english.c +++ b/src/translation/english.c @@ -112,7 +112,7 @@ static translation_string all_strings[] = { {TR_CONFIG_DRAW_CLOUD_SHADOWS, "Draw cloud shadows"}, {TR_CONFIG_ASK_CONFIRMATION_ON_FILE_OVERWRITE, "Ask for confirmation when overwriting a file"}, {TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS, "Non-military gates default to allowing all walkers"}, - {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Advanced tax & wage sentiment contribution logic"}, + {TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, "Advanced tax and wage sentiment contribution logic"}, {TR_HOTKEY_TITLE, "Augustus hotkey configuration"}, {TR_HOTKEY_LABEL, "Hotkey"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternative"}, From 1bc7bef4e1f2bd40d9ccbf836bea39792a468210 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 13 Jan 2025 07:44:28 -0500 Subject: [PATCH 03/25] introduce faster sentiment drop, refactoring --- src/city/sentiment.c | 77 +++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index d5bc23b5c2..d0f32bec26 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -169,11 +169,12 @@ static int get_games_bonus(void) static int get_wage_sentiment_modifier(void) { const int wage_interval = 8; + int use_advanced_sentiment_contribution = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION); int wage_differential = city_data.labor.wages - city_data.labor.wages_rome; - if (wage_differential > wage_interval && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + if (use_advanced_sentiment_contribution && wage_differential > wage_interval) { // Precomputed wage sentiment contributions by intervals. Each next interval gives twice less // contribution in compare to previous, making it inefficient to set wages much higher than Rome. - // When wages differential is more than 32 percent points, it stops contributing to sentiment. + // When wages differential is more than 32 dn, it stops contributing to sentiment. const int contribution_div[4] = { 1, 2, 4, 8 }; // Divisors for the remainder const int contribution[4] = { 8, 12, 14, 15 }; // Precomputed results for full wage intervals const int max_interval_idx = sizeof(contribution) / sizeof(contribution[0]); @@ -188,6 +189,24 @@ static int get_wage_sentiment_modifier(void) int remainder = (wage_differential % wage_interval) * WAGE_POSITIVE_MODIFIER / contribution_div[interval_idx]; wage_differential = contribution[interval_idx - 1] * WAGE_POSITIVE_MODIFIER + remainder; } + } else if (use_advanced_sentiment_contribution && wage_differential < -wage_interval) { + int abs_wage_differential = abs(wage_differential); + // Precomputed wage sentiment punishment by intervals. Each next interval gives doubled + // punishment in compare to previous, making it inefficient to set wages much lower than Rome. + // When wages differential is less than -48 dn, the punishment for every next denarii is at fixed rate + const int punishment[6] = { -8, -24, -56, -120, -248, -504 }; // Precomputed results for full wage intervals + const int max_interval_idx = sizeof(punishment) / sizeof(punishment[0]); + + // Determine the interval index and remainder punishment + int interval_idx = abs_wage_differential / wage_interval; + if (interval_idx >= max_interval_idx) { + // Use the fixed punishment modifier for values out of pre-computed intervals range. + int remainder = (abs_wage_differential - (max_interval_idx * wage_interval)) << max_interval_idx; + wage_differential = (punishment[max_interval_idx - 1] - remainder) * WAGE_NEGATIVE_MODIFIER; + } else { + int remainder = (abs_wage_differential % wage_interval) * (2 << (interval_idx - 1)); + wage_differential = (punishment[interval_idx - 1] - remainder) * WAGE_NEGATIVE_MODIFIER; + } } else { wage_differential *= (wage_differential > 0 ? WAGE_POSITIVE_MODIFIER : WAGE_NEGATIVE_MODIFIER); } @@ -206,24 +225,32 @@ static int get_unemployment_sentiment_modifier(void) static int get_sentiment_modifier_for_tax_rate(int tax) { int base_tax = difficulty_base_tax_rate(); - int tax_differential = base_tax - tax; - tax_differential *= tax_differential < 0 ? (MAX_TAX_MULTIPLIER - base_tax) : (base_tax / 2); - if (tax_differential < 0 && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { - // Extra sentiment punishment applies when player sets higher taxes. - // Multiplier is a power of 2, where exponent is doubled after tax difference - // reaches next interval, which is half of base tax rate. + int interval = calc_bound(base_tax / 2, 1, 8); // Calculate the tax interval length based on difficulty + int sentiment_modifier = base_tax - tax; // The original base sentiment modifier if advanced logic isn't enabled + if (sentiment_modifier < -interval && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + // Extra sentiment punishment modifier applies when player sets higher taxes. Tax range is + // divided by intervals which length is half of base tax rate based on difficulty settings. + // For every next tax interval the modifier is doubled. // Example: - // In very hard mode the base tax rate is 6%. Player sets current tax level to 15%. - // Tax difference is 9%. The interval is 6% / 2 = 3%. It means that for every next 3% of tax - // higher than 6% the tax sentiment multiplier will be doubled. This gives us a tax differential - // value (6% - 15%) * (12% - 6%) * 2^(9% / 3%) = -9% * 6% * 8 = -432 (original value was -54). - int interval = calc_bound(base_tax / 2, 2, 8); - int tax_diff = tax - base_tax; - if (tax_diff >= interval) { - tax_differential *= 2 << calc_bound(tax_diff / interval - 1, 0, 8); + // In very hard mode the base tax rate is 6%. Player sets current tax level to 16%. + // Tax difference will be 10% and the interval length is 3% (half of base tax rate 6%). + // Punishment modifier will be set for every tax interval to values [1, 2, 4, 8]. + // The final modifier: -(3% * 1 + 3% * 2 + 3% * 4 + 1% * 8) * (12% - 6%) = -174 (original value was -60). + int remaining = abs(sentiment_modifier); + sentiment_modifier = 0; + + int modifier = 1; + while (remaining > 0) { + int diff = calc_bound(remaining, 1, interval); + sentiment_modifier -= diff * modifier; + remaining -= diff; + if (modifier < 512) { + modifier <<= 1; // Multiply by 2 + } } } - return tax_differential; + sentiment_modifier *= sentiment_modifier < 0 ? (MAX_TAX_MULTIPLIER - base_tax) : (base_tax / 2); + return sentiment_modifier; } static int get_average_housing_level(void) @@ -358,9 +385,23 @@ void city_sentiment_update(void) sentiment += blessing_festival_boost; + sentiment = calc_bound(sentiment, 0, 100); // new sentiment value should be in range of 0..100 + // Change sentiment gradually to the new value int sentiment_delta = sentiment - b->sentiment.house_happiness; - sentiment_delta = calc_bound(sentiment_delta, -MAX_SENTIMENT_CHANGE, MAX_SENTIMENT_CHANGE); + if (sentiment_delta < 0 && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + // With new advanced logic we introduce faster sentiment drop when the target value is + // much lower than current happiness level. The final sentiment change is a half of the + // percent difference between current happiness level and the target. + // Example: + // Current house happiness level is 82, the new sentiment value is 10 and the delta is -72. + // The delta percent relative to the current happiness level is 87% (72 * 100% / 82). + // The final happiness change will be -30 (43% of -72, which is half of delta percent above). + int delta_percent = abs(sentiment_delta) * 100 / b->sentiment.house_happiness; + sentiment_delta = calc_bound(sentiment_delta * delta_percent / 200, -100, -1); + } else { + sentiment_delta = calc_bound(sentiment_delta, -MAX_SENTIMENT_CHANGE, MAX_SENTIMENT_CHANGE); + } b->sentiment.house_happiness = calc_bound(b->sentiment.house_happiness + sentiment_delta, 0, 100); houses_calculated++; From 51fde7b5b1308a409633b057be3a7994aac3cea6 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 13 Jan 2025 20:38:36 -0500 Subject: [PATCH 04/25] add missed ini key entry --- src/core/config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/config.c b/src/core/config.c index 303f0947d5..1b02fe3c1c 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -72,6 +72,7 @@ static const char *ini_keys[] = { "gameplay_change_yearly_autosave", "gameplay_change_auto_kill_animals", "gameplay_change_nonmilitary_gates_allow_walkers", + "gameplay_change_advanced_tax_wage_sentiment_contribution", "ui_show_speedrun_info", "ui_show_desirability_range", }; From 04c5d9104549f10bbb3847488b083b61d3d4770b Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 14 Jan 2025 13:05:36 -0500 Subject: [PATCH 05/25] move advanced tax and wage logic to difficulty tab --- src/window/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window/config.c b/src/window/config.c index aad2d8aa4a..5e83352e77 100644 --- a/src/window/config.c +++ b/src/window/config.c @@ -238,6 +238,7 @@ static config_widget all_widgets[CONFIG_PAGES][MAX_WIDGETS] = { {TYPE_CHECKBOX, CONFIG_GP_CH_WOLVES_BLOCK, TR_CONFIG_WOLVES_BLOCK }, {TYPE_CHECKBOX, CONFIG_GP_CH_MULTIPLE_BARRACKS, TR_CONFIG_MULTIPLE_BARRACKS }, {TYPE_CHECKBOX, CONFIG_GP_CH_DISABLE_INFINITE_WOLVES_SPAWNING, TR_CONFIG_GP_CH_DISABLE_INFINITE_WOLVES_SPAWNING }, + {TYPE_CHECKBOX, CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION}, {TYPE_NUMERICAL_DESC, RANGE_MAX_GRAND_TEMPLES, TR_CONFIG_MAX_GRAND_TEMPLES}, {TYPE_NUMERICAL_RANGE, RANGE_MAX_GRAND_TEMPLES, 0, display_text_max_grand_temples}, }, @@ -256,7 +257,6 @@ static config_widget all_widgets[CONFIG_PAGES][MAX_WIDGETS] = { {TYPE_CHECKBOX, CONFIG_GP_CH_ROAMERS_DONT_SKIP_CORNERS, TR_CONFIG_ROAMERS_DONT_SKIP_CORNERS }, {TYPE_CHECKBOX, CONFIG_GP_CH_AUTO_KILL_ANIMALS, TR_CONFIG_AUTO_KILL_ANIMALS}, {TYPE_CHECKBOX, CONFIG_GP_CH_GATES_DEFAULT_TO_PASS_ALL_WALKERS, TR_CONFIG_GATES_DEFAULT_TO_PASS_ALL_WALKERS}, - {TYPE_CHECKBOX, CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION, TR_CONFIG_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION}, } }; From 618838ec0a5265107bd3872afcab00bcbd54c975 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 14 Jan 2025 16:15:01 -0500 Subject: [PATCH 06/25] add faster sentiment gain, new gain/loss logic is enabled only after 30 months passed --- src/city/sentiment.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index d0f32bec26..a545c5e786 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -13,6 +13,7 @@ #include "core/config.h" #include "core/random.h" #include "game/difficulty.h" +#include "game/time.h" #include "game/tutorial.h" #include @@ -35,6 +36,11 @@ #define IMPERIAL_GAMES_SENTIMENT_BONUS 15 #define POP_STEP_FOR_BASE_AVERAGE_HOUSE_LEVEL 625 +// New advanced sentiment change calculation applies only after configured months +// of gameplay has passed. This is required to prevent very fast sentiment drop +// by high unemployment at very early game +#define ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS 30 + int city_sentiment(void) { return city_data.sentiment.value; @@ -389,16 +395,30 @@ void city_sentiment_update(void) // Change sentiment gradually to the new value int sentiment_delta = sentiment - b->sentiment.house_happiness; - if (sentiment_delta < 0 && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { - // With new advanced logic we introduce faster sentiment drop when the target value is - // much lower than current happiness level. The final sentiment change is a half of the - // percent difference between current happiness level and the target. - // Example: + if (sentiment_delta != 0 && + game_time_total_months() >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS && + config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + // With new advanced logic we introduce faster sentiment change when the target value is + // far away from current happiness level. For the negative delta the final + // sentiment change is a half of the delta difference percent. For the positive delta + // the final sentiment change is 1/8 of the delta difference percent. + // Example #1: // Current house happiness level is 82, the new sentiment value is 10 and the delta is -72. // The delta percent relative to the current happiness level is 87% (72 * 100% / 82). // The final happiness change will be -30 (43% of -72, which is half of delta percent above). - int delta_percent = abs(sentiment_delta) * 100 / b->sentiment.house_happiness; - sentiment_delta = calc_bound(sentiment_delta * delta_percent / 200, -100, -1); + // Example #2: + // Current house happiness level is 20, the new sentiment value is 77 and the delta is 57. + // The delta percent relative to the current happiness level is 74% (57 * 100% / 77). + // The final happiness change will be 5 (9% of 57). + if (sentiment_delta > 0) { + int happiness_target = calc_bound(b->sentiment.house_happiness + sentiment_delta, 1, 100); + int delta_percent = sentiment_delta * 100 / happiness_target; + sentiment_delta = calc_bound(sentiment_delta * delta_percent / 800, 1, 100); + } else { + int delta_percent = b->sentiment.house_happiness == 0 ? + 100 : (-sentiment_delta * 100 / b->sentiment.house_happiness); + sentiment_delta = calc_bound(sentiment_delta * delta_percent / 200, -100, -1); + } } else { sentiment_delta = calc_bound(sentiment_delta, -MAX_SENTIMENT_CHANGE, MAX_SENTIMENT_CHANGE); } From 9a7f86457a61b3f7370456bafab17acbacc414d4 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Wed, 15 Jan 2025 20:55:52 -0500 Subject: [PATCH 07/25] adjust gain/drop modifiers by difficulty --- src/city/sentiment.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index a545c5e786..cea56cabff 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -13,6 +13,7 @@ #include "core/config.h" #include "core/random.h" #include "game/difficulty.h" +#include "game/settings.h" #include "game/time.h" #include "game/tutorial.h" @@ -320,6 +321,22 @@ static int extra_food_bonus(int types, int required) return calc_bound(extra, 0, MAX_SENTIMENT_FROM_EXTRA_FOOD); } +const advanced_sentiment_gain_modifier[5] = { + 400, // 25% + 463, // 21.6% + 546, // 18.3% + 666, // 15% + 800 // 12.5% +}; + +const advanced_sentiment_drop_modifier[5] = { + 400, // 25% + 333, // 30% + 285, // 35% + 250, // 40% + 200 // 50% +}; + void city_sentiment_update(void) { city_population_check_consistency(); @@ -413,11 +430,13 @@ void city_sentiment_update(void) if (sentiment_delta > 0) { int happiness_target = calc_bound(b->sentiment.house_happiness + sentiment_delta, 1, 100); int delta_percent = sentiment_delta * 100 / happiness_target; - sentiment_delta = calc_bound(sentiment_delta * delta_percent / 800, 1, 100); + int gain_modifier = advanced_sentiment_gain_modifier[setting_difficulty()]; + sentiment_delta = calc_bound(sentiment_delta * delta_percent / gain_modifier, 1, 100); } else { int delta_percent = b->sentiment.house_happiness == 0 ? 100 : (-sentiment_delta * 100 / b->sentiment.house_happiness); - sentiment_delta = calc_bound(sentiment_delta * delta_percent / 200, -100, -1); + int drop_modifier = advanced_sentiment_drop_modifier[setting_difficulty()]; + sentiment_delta = calc_bound(sentiment_delta * delta_percent / drop_modifier, -100, -1); } } else { sentiment_delta = calc_bound(sentiment_delta, -MAX_SENTIMENT_CHANGE, MAX_SENTIMENT_CHANGE); From dc46c8b15e1d861ff88a0c1f04ad5dc077e6e133 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Wed, 15 Jan 2025 21:01:30 -0500 Subject: [PATCH 08/25] make changes to the comments --- src/city/sentiment.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index cea56cabff..294563b030 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -416,17 +416,16 @@ void city_sentiment_update(void) game_time_total_months() >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { // With new advanced logic we introduce faster sentiment change when the target value is - // far away from current happiness level. For the negative delta the final - // sentiment change is a half of the delta difference percent. For the positive delta - // the final sentiment change is 1/8 of the delta difference percent. + // far away from current happiness level. The final change value depends on difficulty settings. // Example #1: // Current house happiness level is 82, the new sentiment value is 10 and the delta is -72. // The delta percent relative to the current happiness level is 87% (72 * 100% / 82). - // The final happiness change will be -30 (43% of -72, which is half of delta percent above). + // The final happiness change for VeryHard mode will be -30 (43% of -72, which is + // 50% of delta percent). // Example #2: // Current house happiness level is 20, the new sentiment value is 77 and the delta is 57. // The delta percent relative to the current happiness level is 74% (57 * 100% / 77). - // The final happiness change will be 5 (9% of 57). + // The final happiness change for Hard mode will be 5 (11% of 57, which is 15% of delta percent). if (sentiment_delta > 0) { int happiness_target = calc_bound(b->sentiment.house_happiness + sentiment_delta, 1, 100); int delta_percent = sentiment_delta * 100 / happiness_target; From 91135dcea761e8762ac8af230bdb43ebbb0cc311 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Wed, 15 Jan 2025 21:02:14 -0500 Subject: [PATCH 09/25] fix example #2 in explanation comment --- src/city/sentiment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 294563b030..1bcb0c0fff 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -425,7 +425,7 @@ void city_sentiment_update(void) // Example #2: // Current house happiness level is 20, the new sentiment value is 77 and the delta is 57. // The delta percent relative to the current happiness level is 74% (57 * 100% / 77). - // The final happiness change for Hard mode will be 5 (11% of 57, which is 15% of delta percent). + // The final happiness change for Hard mode will be 6 (11% of 57, which is 15% of delta percent). if (sentiment_delta > 0) { int happiness_target = calc_bound(b->sentiment.house_happiness + sentiment_delta, 1, 100); int delta_percent = sentiment_delta * 100 / happiness_target; From 57a99e0ac1e1420620dd7a083e83ba5a896310f6 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Wed, 15 Jan 2025 23:44:44 -0500 Subject: [PATCH 10/25] add new sentiment change logic cooldown for newly built houses --- src/building/building.c | 16 ++++++++++++++++ src/building/building.h | 23 ++++++++++++++++++++++- src/building/state.c | 8 ++++++-- src/city/gods.c | 4 ++-- src/city/sentiment.c | 41 ++++++++++++++++++++++++++++++++++++----- src/city/sentiment.h | 2 +- src/game/tick.c | 5 +++-- 7 files changed, 86 insertions(+), 13 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index b26c3d0e1a..a730835a56 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -172,6 +172,21 @@ static void remove_adjacent_types(building *b) b->next_of_type = 0; } +void initialize_sentiment_cooldown(building *b) { + if (b->extra_house_info.sentiment_cooldown_initialized) { + return; + } + + b->extra_house_info.sentiment_cooldown_initialized = 1; + + if (b->type <= BUILDING_HOUSE_GRAND_INSULA) { + b->extra_house_info.sentiment_cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; + } else { + // Do not apply cooldown to villas + b->extra_house_info.sentiment_cooldown = 0; + } +} + building *building_create(building_type type, int x, int y) { building *b; @@ -205,6 +220,7 @@ building *building_create(building_type type, int x, int y) // subtype if (building_is_house(type)) { + initialize_sentiment_cooldown(b); b->subtype.house_level = type - BUILDING_HOUSE_VACANT_LOT; } diff --git a/src/building/building.h b/src/building/building.h index 37010da2fc..fb68892631 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -7,6 +7,14 @@ #include "game/resource.h" #include "translation/translation.h" +// Ticks of cooldown before new advanced sentiment logic will be applied +// for the house building. Each tick is equal to 3 months. That value +// shouldn't ever exceed 7, since it takes 3 bits of data. +// To extend or reduce the cooldown duration edit the +// ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS preprocessor definition. +#define ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS 7 +#define ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS 3 + typedef enum order_condition_type { ORDER_CONDITION_NEVER = 0, ORDER_CONDITION_ALWAYS, @@ -175,7 +183,18 @@ typedef struct building { signed char desirability; unsigned char is_deleted; unsigned char is_adjacent_to_water; - unsigned char storage_id; + union { + unsigned char storage_id; + // New advanced sentiment contribution logic requires cooldown for newly built houses. + // The new happiness gain/drop logic will not be applied until cooldown expires. + // Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total. + // That should be enough to build new housing block and evolve it. + struct { + uint8_t sentiment_cooldown_initialized: 1; + uint8_t sentiment_cooldown: 3; + uint8_t reserved: 4; + } extra_house_info; + }; union { signed char house_happiness; signed char native_anger; @@ -220,6 +239,8 @@ building *building_main(building *b); building *building_next(building *b); +void initialize_sentiment_cooldown(building *b); + building *building_create(building_type type, int x, int y); void building_clear_related_data(building *b); diff --git a/src/building/state.c b/src/building/state.c index 326df7f687..f5fcdc1e3c 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -162,7 +162,7 @@ void building_state_save_to_buffer(buffer *buf, const building *b) buffer_write_i8(buf, b->desirability); buffer_write_u8(buf, b->is_deleted); buffer_write_u8(buf, b->is_adjacent_to_water); - buffer_write_u8(buf, b->storage_id); + buffer_write_u8(buf, b->storage_id); // which union field we use does not matter buffer_write_i8(buf, b->sentiment.house_happiness); // which union field we use does not matter buffer_write_u8(buf, b->show_on_problem_overlay); @@ -486,7 +486,7 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->desirability = buffer_read_i8(buf); b->is_deleted = buffer_read_u8(buf); b->is_adjacent_to_water = buffer_read_u8(buf); - b->storage_id = buffer_read_u8(buf); + b->storage_id = buffer_read_u8(buf); // which union field we use does not matter b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter b->show_on_problem_overlay = buffer_read_u8(buf); @@ -687,4 +687,8 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ if (building_buf_size > BUILDING_STATE_CURRENT_BUFFER_SIZE) { buffer_skip(buf, building_buf_size - BUILDING_STATE_CURRENT_BUFFER_SIZE); } + + if (building_is_house(b->type)) { + initialize_sentiment_cooldown(b); + } } diff --git a/src/city/gods.c b/src/city/gods.c index c36c955d39..c689ef40c7 100644 --- a/src/city/gods.c +++ b/src/city/gods.c @@ -115,7 +115,7 @@ static void perform_small_curse(god_type god) city_message_post(1, MESSAGE_VENUS_IS_UPSET, 0, 0); city_data.sentiment.blessing_festival_boost -= 15; city_health_change(-10); - city_sentiment_update(); + city_sentiment_update(0); break; } } @@ -162,7 +162,7 @@ static int perform_large_curse(god_type god) city_health_change(-20); } city_data.religion.venus_curse_active = 1; - city_sentiment_update(); + city_sentiment_update(0); break; } return 1; diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 1bcb0c0fff..ee6032e4e0 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -321,7 +321,7 @@ static int extra_food_bonus(int types, int required) return calc_bound(extra, 0, MAX_SENTIMENT_FROM_EXTRA_FOOD); } -const advanced_sentiment_gain_modifier[5] = { +const int advanced_sentiment_gain_modifier[5] = { 400, // 25% 463, // 21.6% 546, // 18.3% @@ -329,7 +329,7 @@ const advanced_sentiment_gain_modifier[5] = { 800 // 12.5% }; -const advanced_sentiment_drop_modifier[5] = { +const int advanced_sentiment_drop_modifier[5] = { 400, // 25% 333, // 30% 285, // 35% @@ -337,7 +337,36 @@ const advanced_sentiment_drop_modifier[5] = { 200 // 50% }; -void city_sentiment_update(void) +// Checks if house building still has a cooldown before apply advanced sentiment change logic +int is_house_has_ongoing_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { + if (!building_is_house(b->type) || !b->extra_house_info.sentiment_cooldown_initialized) { + return 0; + } + + if (b->type > BUILDING_HOUSE_GRAND_INSULA) { + // Reset cooldown for villas + b->extra_house_info.sentiment_cooldown = 0; + } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->extra_house_info.sentiment_cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { + // Wait for new citizens to arrive + return 1; + } + + if (update_sentiment_cooldown && + b->extra_house_info.sentiment_cooldown && + game_time_month() % ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS == 0) { + // Decrease tick once configured amount of game months has passed. + b->extra_house_info.sentiment_cooldown--; + } + + if (!b->extra_house_info.sentiment_cooldown) { + // Cooldown has ended + return 0; + } + + return 1; +} + +void city_sentiment_update(int update_sentiment_cooldown) { city_population_check_consistency(); @@ -356,6 +385,8 @@ void city_sentiment_update(void) int total_pop = 0; int total_houses = 0; int house_level_sentiment_multiplier = 3; + int apply_advanced_sentiment_change = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION) && + game_time_total_months() >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS; for (building_type type = BUILDING_HOUSE_SMALL_TENT; type <= BUILDING_HOUSE_LUXURY_PALACE; type++) { if (type == BUILDING_HOUSE_SMALL_SHACK) { @@ -413,8 +444,8 @@ void city_sentiment_update(void) // Change sentiment gradually to the new value int sentiment_delta = sentiment - b->sentiment.house_happiness; if (sentiment_delta != 0 && - game_time_total_months() >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS && - config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { + apply_advanced_sentiment_change && + !is_house_has_ongoing_advanced_sentiment_change_cooldown(b, update_sentiment_cooldown)) { // With new advanced logic we introduce faster sentiment change when the target value is // far away from current happiness level. The final change value depends on difficulty settings. // Example #1: diff --git a/src/city/sentiment.h b/src/city/sentiment.h index bb87fa2ad3..02db1c9ba6 100644 --- a/src/city/sentiment.h +++ b/src/city/sentiment.h @@ -25,6 +25,6 @@ void city_sentiment_reduce_crime_cooldown(void); int city_sentiment_get_blessing_festival_boost(void); void city_sentiment_decrement_blessing_boost(void); -void city_sentiment_update(void); +void city_sentiment_update(int update_sentiment_cooldown); #endif // CITY_SENTIMENT_H diff --git a/src/game/tick.c b/src/game/tick.c index d5b8a4f895..81db97f958 100644 --- a/src/game/tick.c +++ b/src/game/tick.c @@ -130,8 +130,9 @@ static void advance_day(void) if (game_time_advance_day()) { advance_month(); } - if (game_time_day() == 0 || game_time_day() == 8) { - city_sentiment_update(); + int update_sentiment_cooldown = game_time_day() == 0; + if (update_sentiment_cooldown || game_time_day() == 8) { + city_sentiment_update(update_sentiment_cooldown); } if (game_time_day() == 0 || game_time_day() == 7) { building_lighthouse_consume_timber(); From 4979e7e109ef7254d930e5259390e9cf6a216c39 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Thu, 16 Jan 2025 07:07:31 -0500 Subject: [PATCH 11/25] prevent compile warning by add a name to union (extra_attr) which shares storage_id/sentiment_cooldown --- src/building/building.c | 14 +++++++------- src/building/building.h | 4 ++-- src/building/construction_building.c | 4 ++-- src/building/data_transfer.c | 6 +++--- src/building/granary.c | 16 ++++++++-------- src/building/state.c | 4 ++-- src/building/storage.c | 14 +++++++------- src/building/warehouse.c | 16 ++++++++-------- src/city/sentiment.c | 12 ++++++------ src/figuretype/cartpusher.c | 2 +- src/figuretype/depot.c | 4 ++-- src/figuretype/docker.c | 4 ++-- src/figuretype/trader.c | 6 +++--- src/game/undo.c | 2 +- src/widget/city_overlay_other.c | 6 +++--- src/widget/city_without_overlay.c | 2 +- src/window/building/depot.c | 14 +++++++------- src/window/building/distribution.c | 20 ++++++++++---------- src/window/building/figures.c | 6 +++--- 19 files changed, 78 insertions(+), 78 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index a730835a56..197dcdea7d 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -173,17 +173,17 @@ static void remove_adjacent_types(building *b) } void initialize_sentiment_cooldown(building *b) { - if (b->extra_house_info.sentiment_cooldown_initialized) { + if (b->extra_attr.house.sentiment_cooldown_initialized) { return; } - b->extra_house_info.sentiment_cooldown_initialized = 1; + b->extra_attr.house.sentiment_cooldown_initialized = 1; if (b->type <= BUILDING_HOUSE_GRAND_INSULA) { - b->extra_house_info.sentiment_cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; + b->extra_attr.house.sentiment_cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; } else { // Do not apply cooldown to villas - b->extra_house_info.sentiment_cooldown = 0; + b->extra_attr.house.sentiment_cooldown = 0; } } @@ -284,9 +284,9 @@ static void building_delete(building *b) void building_clear_related_data(building *b) { - if (b->storage_id) { - building_storage_delete(b->storage_id); - b->storage_id = 0; + if (b->extra_attr.storage_id) { + building_storage_delete(b->extra_attr.storage_id); + b->extra_attr.storage_id = 0; } if (b->type == BUILDING_FORT) { formation_legion_delete_for_fort(b); diff --git a/src/building/building.h b/src/building/building.h index fb68892631..a241214614 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -193,8 +193,8 @@ typedef struct building { uint8_t sentiment_cooldown_initialized: 1; uint8_t sentiment_cooldown: 3; uint8_t reserved: 4; - } extra_house_info; - }; + } house; + } extra_attr; union { signed char house_happiness; signed char native_anger; diff --git a/src/building/construction_building.c b/src/building/construction_building.c index 448da773d4..a9460b6e4d 100644 --- a/src/building/construction_building.c +++ b/src/building/construction_building.c @@ -106,7 +106,7 @@ static void add_warehouse(building *b) int y_offset[9] = { 0, 1, 0, 1, 2, 0, 2, 1, 2 }; int corner = building_rotation_get_corner(2 * building_rotation_get_rotation()); - b->storage_id = building_storage_create(b->id); + b->extra_attr.storage_id = building_storage_create(b->id); b->prev_part_building_id = 0; map_building_tiles_add(b->id, b->x + x_offset[corner], b->y + y_offset[corner], 1, image_group(GROUP_BUILDING_WAREHOUSE), TERRAIN_BUILDING); @@ -145,7 +145,7 @@ static void add_depot(building *b) static void add_granary(building *b) { - b->storage_id = building_storage_create(b->id); + b->extra_attr.storage_id = building_storage_create(b->id); add_building(b); map_tiles_update_area_roads(b->x, b->y, 5); } diff --git a/src/building/data_transfer.c b/src/building/data_transfer.c index 14216991bf..f22803e4f4 100644 --- a/src/building/data_transfer.c +++ b/src/building/data_transfer.c @@ -51,11 +51,11 @@ int building_data_transfer_copy(building *b) memcpy(data.resource, b->accepted_goods, sizeof(unsigned char) * RESOURCE_MAX); break; case DATA_TYPE_GRANARY: - storage = building_storage_get(b->storage_id); + storage = building_storage_get(b->extra_attr.storage_id); data.storage = *storage; break; case DATA_TYPE_WAREHOUSE: - storage = building_storage_get(b->storage_id); + storage = building_storage_get(b->extra_attr.storage_id); data.storage = *storage; break; case DATA_TYPE_DOCK: @@ -94,7 +94,7 @@ int building_data_transfer_paste(building *b) break; case DATA_TYPE_GRANARY: case DATA_TYPE_WAREHOUSE: - building_storage_set_data(b->storage_id, data.storage); + building_storage_set_data(b->extra_attr.storage_id, data.storage); break; case DATA_TYPE_DOCK: memcpy(b->accepted_goods, data.resource, sizeof(unsigned char) * RESOURCE_MAX); diff --git a/src/building/granary.c b/src/building/granary.c index 39ea13da5f..695a3f2353 100644 --- a/src/building/granary.c +++ b/src/building/granary.c @@ -41,7 +41,7 @@ static int get_amount(building *granary, int resource) static int granary_is_accepting(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int amount = get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_ACCEPTING) || @@ -56,7 +56,7 @@ static int granary_is_accepting(int resource, building *b) int building_granary_is_getting(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int amount = get_amount(b, resource); return !b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || @@ -67,7 +67,7 @@ int building_granary_is_getting(int resource, building *b) static int granary_is_gettable(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); return !b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || (s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING_3QUARTERS) || @@ -286,7 +286,7 @@ int building_granary_maximum_receptible_amount(int resource, building *b) } int stored_amount = b->resources[resource]; int max_amount; - switch (building_storage_get(b->storage_id)->resource_state[resource]) { + switch (building_storage_get(b->extra_attr.storage_id)->resource_state[resource]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: max_amount = FULL_GRANARY; @@ -350,7 +350,7 @@ int building_granary_determine_worker_task(building *granary) if (pct_workers < 50) { return GRANARY_TASK_NONE; } - const building_storage *s = building_storage_get(granary->storage_id); + const building_storage *s = building_storage_get(granary->extra_attr.storage_id); if (s->empty_all) { // bring food to another granary for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) { @@ -418,7 +418,7 @@ int building_granary_accepts_storage(building *b, int resource, int *understaffe } return 0; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (building_granary_is_not_accepting(resource, b) || s->empty_all) { return 0; } @@ -488,7 +488,7 @@ int building_getting_granary_for_storing(int x, int y, int resource, int road_ne if (pct_workers < 100) { continue; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (!building_granary_is_getting(resource, b) || s->empty_all) { continue; } @@ -520,7 +520,7 @@ int building_granary_amount_can_get_from(building *destination, building *origin int building_granary_for_getting(building *src, map_point *dst, int min_amount) { - const building_storage *s_src = building_storage_get(src->storage_id); + const building_storage *s_src = building_storage_get(src->extra_attr.storage_id); if (s_src->empty_all) { return 0; } diff --git a/src/building/state.c b/src/building/state.c index f5fcdc1e3c..f4dcf97e2f 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -162,7 +162,7 @@ void building_state_save_to_buffer(buffer *buf, const building *b) buffer_write_i8(buf, b->desirability); buffer_write_u8(buf, b->is_deleted); buffer_write_u8(buf, b->is_adjacent_to_water); - buffer_write_u8(buf, b->storage_id); // which union field we use does not matter + buffer_write_u8(buf, b->extra_attr.storage_id); // which union field we use does not matter buffer_write_i8(buf, b->sentiment.house_happiness); // which union field we use does not matter buffer_write_u8(buf, b->show_on_problem_overlay); @@ -486,7 +486,7 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->desirability = buffer_read_i8(buf); b->is_deleted = buffer_read_u8(buf); b->is_adjacent_to_water = buffer_read_u8(buf); - b->storage_id = buffer_read_u8(buf); // which union field we use does not matter + b->extra_attr.storage_id = buffer_read_u8(buf); // which union field we use does not matter b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter b->show_on_problem_overlay = buffer_read_u8(buf); diff --git a/src/building/storage.c b/src/building/storage.c index e20279593e..e92f27e15d 100644 --- a/src/building/storage.c +++ b/src/building/storage.c @@ -60,12 +60,12 @@ void building_storage_reset_building_ids(void) if (b->state == BUILDING_STATE_UNUSED) { continue; } - if (b->storage_id) { - if (array_item(storages, b->storage_id)->building_id) { + if (b->extra_attr.storage_id) { + if (array_item(storages, b->extra_attr.storage_id)->building_id) { // storage is already connected to a building: corrupt, create new - b->storage_id = building_storage_create(b->id); + b->extra_attr.storage_id = building_storage_create(b->id); } else { - array_item(storages, b->storage_id)->building_id = b->id; + array_item(storages, b->extra_attr.storage_id)->building_id = b->id; } } } @@ -160,12 +160,12 @@ void building_storage_cycle_resource_state(int storage_id, resource_type resourc void building_storage_set_permission(building_storage_permission_states p, building *b) { int permission_bit = 1 << p; - array_item(storages, b->storage_id)->storage.permissions ^= permission_bit; + array_item(storages, b->extra_attr.storage_id)->storage.permissions ^= permission_bit; } int building_storage_get_permission(building_storage_permission_states p, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int permission_bit = 1 << p; return !(s->permissions & permission_bit); } @@ -229,7 +229,7 @@ int building_storage_resource_max_storable(building *b, resource_type resource_i return 0; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); switch (s->resource_state[resource_id]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: diff --git a/src/building/warehouse.c b/src/building/warehouse.c index 53cd56ec28..0c4343ebb5 100644 --- a/src/building/warehouse.c +++ b/src/building/warehouse.c @@ -275,7 +275,7 @@ static building *get_next_warehouse(void) int building_warehouse_is_accepting(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int amount = building_warehouse_get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_ACCEPTING) || @@ -290,7 +290,7 @@ int building_warehouse_is_accepting(int resource, building *b) int building_warehouse_is_getting(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int amount = building_warehouse_get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || @@ -305,7 +305,7 @@ int building_warehouse_is_getting(int resource, building *b) static int warehouse_is_gettable(int resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || (s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING_HALF) || @@ -324,7 +324,7 @@ int building_warehouse_is_not_accepting(int resource, building *b) static int get_acceptable_quantity(resource_type resource, building *b) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); switch (s->resource_state[resource]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: @@ -476,7 +476,7 @@ int building_warehouse_accepts_storage(building *b, int resource, int *understaf !b->has_road_access || b->distance_from_entry <= 0 || b->has_plague) { return 0; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (building_warehouse_is_not_accepting(resource, b) || s->empty_all) { return 0; } @@ -628,7 +628,7 @@ static int determine_granary_accept_foods(int resources[RESOURCE_MAX_FOOD], int } int pct_workers = calc_percentage(b->num_workers, model_get_building(b->type)->laborers); if (pct_workers >= 100 && b->resources[RESOURCE_NONE] >= 100) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (!s->empty_all) { for (int r = 0; r < RESOURCE_MAX_FOOD; r++) { if (!building_granary_is_not_accepting(r, b)) { @@ -657,7 +657,7 @@ static int determine_granary_get_foods(int resources[RESOURCE_MAX_FOOD], int roa } int pct_workers = calc_percentage(b->num_workers, model_get_building(b->type)->laborers); if (pct_workers >= 100 && b->resources[RESOURCE_NONE] > 100) { - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); if (!s->empty_all) { for (int r = 0; r < RESOURCE_MAX_FOOD; r++) { if (building_granary_is_getting(r, b)) { @@ -692,7 +692,7 @@ int building_warehouse_determine_worker_task(building *warehouse, int *resource) if (pct_workers < 50) { return WAREHOUSE_TASK_NONE; } - const building_storage *s = building_storage_get(warehouse->storage_id); + const building_storage *s = building_storage_get(warehouse->extra_attr.storage_id); building *space; // get resources for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { diff --git a/src/city/sentiment.c b/src/city/sentiment.c index ee6032e4e0..2f010dfc08 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -339,26 +339,26 @@ const int advanced_sentiment_drop_modifier[5] = { // Checks if house building still has a cooldown before apply advanced sentiment change logic int is_house_has_ongoing_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { - if (!building_is_house(b->type) || !b->extra_house_info.sentiment_cooldown_initialized) { + if (!building_is_house(b->type) || !b->extra_attr.house.sentiment_cooldown_initialized) { return 0; } if (b->type > BUILDING_HOUSE_GRAND_INSULA) { // Reset cooldown for villas - b->extra_house_info.sentiment_cooldown = 0; - } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->extra_house_info.sentiment_cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { + b->extra_attr.house.sentiment_cooldown = 0; + } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->extra_attr.house.sentiment_cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { // Wait for new citizens to arrive return 1; } if (update_sentiment_cooldown && - b->extra_house_info.sentiment_cooldown && + b->extra_attr.house.sentiment_cooldown && game_time_month() % ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS == 0) { // Decrease tick once configured amount of game months has passed. - b->extra_house_info.sentiment_cooldown--; + b->extra_attr.house.sentiment_cooldown--; } - if (!b->extra_house_info.sentiment_cooldown) { + if (!b->extra_attr.house.sentiment_cooldown) { // Cooldown has ended return 0; } diff --git a/src/figuretype/cartpusher.c b/src/figuretype/cartpusher.c index 1a818e7119..d1f8a3f61c 100644 --- a/src/figuretype/cartpusher.c +++ b/src/figuretype/cartpusher.c @@ -676,7 +676,7 @@ static void determine_warehouseman_destination(figure *f, int road_network_id, i } // priority 5: another warehouse to empty this one - if (building_storage_get(building_get(f->building_id)->storage_id)->empty_all) { + if (building_storage_get(building_get(f->building_id)->extra_attr.storage_id)->empty_all) { dst_building_id = building_warehouse_for_storing(f->building_id, f->x, f->y, f->resource_id, -1, 0, &dst); // deliver to another warehouse because this one is being emptied diff --git a/src/figuretype/depot.c b/src/figuretype/depot.c index bf42d80445..bc76d6ba4d 100644 --- a/src/figuretype/depot.c +++ b/src/figuretype/depot.c @@ -209,7 +209,7 @@ static int check_valid_storages(order *current_order, int action_state) { int valid_storages = 1; building *src = building_get(current_order->src_storage_id); - if (!src || !src->storage_id || src->state != BUILDING_STATE_IN_USE) { + if (!src || !src->extra_attr.storage_id || src->state != BUILDING_STATE_IN_USE) { if (action_state == FIGURE_ACTION_239_DEPOT_CART_PUSHER_HEADING_TO_SOURCE || action_state == FIGURE_ACTION_240_DEPOT_CART_PUSHER_AT_SOURCE) { valid_storages = 0; @@ -217,7 +217,7 @@ static int check_valid_storages(order *current_order, int action_state) current_order->src_storage_id = 0; } building *dst = building_get(current_order->dst_storage_id); - if (!dst || !dst->storage_id || dst->state != BUILDING_STATE_IN_USE) { + if (!dst || !dst->extra_attr.storage_id || dst->state != BUILDING_STATE_IN_USE) { valid_storages = 0; current_order->dst_storage_id = 0; } diff --git a/src/figuretype/docker.c b/src/figuretype/docker.c index 32df83b6cf..3bb1dcaefd 100644 --- a/src/figuretype/docker.c +++ b/src/figuretype/docker.c @@ -160,7 +160,7 @@ static int get_closest_building_for_import(int x, int y, int city_id, building * int min_building_id = 0; for (building *b = building_first_of_type(BUILDING_WAREHOUSE); b; b = b->next_of_type) { if (is_invalid_destination(b, dock) || - building_storage_get(b->storage_id)->empty_all || + building_storage_get(b->extra_attr.storage_id)->empty_all || building_warehouse_is_not_accepting(resource, b)) { continue; } @@ -189,7 +189,7 @@ static int get_closest_building_for_import(int x, int y, int city_id, building * if (resource_is_food(resource)) { for (building *b = building_first_of_type(BUILDING_GRANARY); b; b = b->next_of_type) { if (is_invalid_destination(b, dock) || - building_storage_get(b->storage_id)->empty_all || + building_storage_get(b->extra_attr.storage_id)->empty_all || building_granary_is_not_accepting(resource, b) || building_granary_is_full(b)) { continue; diff --git a/src/figuretype/trader.c b/src/figuretype/trader.c index d37d4bddc7..1fda25119c 100644 --- a/src/figuretype/trader.c +++ b/src/figuretype/trader.c @@ -140,7 +140,7 @@ int figure_trade_caravan_can_sell(figure *trader, int building_id, int city_id) if (!building_storage_get_permission(BUILDING_STORAGE_PERMISSION_TRADERS, b)) { return 0; } - if (building_storage_get(b->storage_id)->empty_all) { + if (building_storage_get(b->extra_attr.storage_id)->empty_all) { return 0; } if (b->type == BUILDING_GRANARY) { @@ -347,7 +347,7 @@ static int get_closest_storage(const figure *f, int x, int y, int city_id, map_p !building_storage_get_permission(BUILDING_STORAGE_PERMISSION_TRADERS, b)) { continue; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int distance_penalty = 32; int num_imports_for_warehouse = 0; for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { @@ -394,7 +394,7 @@ static int get_closest_storage(const figure *f, int x, int y, int city_id, map_p continue; } - const building_storage *s = building_storage_get(b->storage_id); + const building_storage *s = building_storage_get(b->extra_attr.storage_id); int distance_penalty = 32; for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { int resource = city_trade_next_caravan_import_resource(); diff --git a/src/game/undo.c b/src/game/undo.c index be0743478b..056dde12df 100644 --- a/src/game/undo.c +++ b/src/game/undo.c @@ -222,7 +222,7 @@ void game_undo_perform(void) break; case BUILDING_WAREHOUSE: case BUILDING_GRANARY: - if (!building_storage_restore(b->storage_id)) { + if (!building_storage_restore(b->extra_attr.storage_id)) { building_storage_reset_building_ids(); } break; diff --git a/src/widget/city_overlay_other.c b/src/widget/city_overlay_other.c index 3d93457a44..aa8072a928 100644 --- a/src/widget/city_overlay_other.c +++ b/src/widget/city_overlay_other.c @@ -116,7 +116,7 @@ static int show_building_logistics(const building *b) static int show_building_storages(const building *b) { b = building_main((building *) b); - return b->storage_id > 0 && building_storage_get(b->storage_id); + return b->extra_attr.storage_id > 0 && building_storage_get(b->extra_attr.storage_id); } static int show_building_none(const building *b) @@ -915,12 +915,12 @@ static void draw_storage_ids(int x, int y, float scale, int grid_offset) } int building_id = map_building_at(grid_offset); building *b = building_get(building_id); - if (!b || b->is_deleted || map_property_is_deleted(b->grid_offset) || !b->storage_id || + if (!b || b->is_deleted || map_property_is_deleted(b->grid_offset) || !b->extra_attr.storage_id || !map_property_is_draw_tile(grid_offset)) { return; } uint8_t number[10]; - string_from_int(number, b->storage_id, 0); + string_from_int(number, b->extra_attr.storage_id, 0); int text_width = text_get_width(number, FONT_SMALL_PLAIN); int box_width = text_width + 10; int box_height = 22; diff --git a/src/widget/city_without_overlay.c b/src/widget/city_without_overlay.c index 5b4957cba5..91d904e58a 100644 --- a/src/widget/city_without_overlay.c +++ b/src/widget/city_without_overlay.c @@ -592,7 +592,7 @@ static void draw_permissions_flag(building *b, int x, int y, color_t color_mask) base_permission_image[6] = assets_get_image_id("UI", "Warehouse_Flag_Land_Sea"); base_permission_image[7] = assets_get_image_id("UI", "Warehouse_Flag_All"); } - const building_storage *storage = building_storage_get(b->storage_id); + const building_storage *storage = building_storage_get(b->extra_attr.storage_id); int flag_permission_mask = 0x7; int permissions = (~storage->permissions) & flag_permission_mask; if (!permissions) { diff --git a/src/window/building/depot.c b/src/window/building/depot.c index 764394f224..c3fbd68868 100644 --- a/src/window/building/depot.c +++ b/src/window/building/depot.c @@ -145,7 +145,7 @@ static void setup_buttons_for_selected_depot(void) continue; } building *store_building = building_get(storage->building_id); - if (building_is_active(store_building) && store_building->storage_id == storage->id && + if (building_is_active(store_building) && store_building->extra_attr.storage_id == storage->id && building_storage_resource_max_storable(store_building, data.target_resource_id) > 0) { current_storage_offset++; if (current_storage_offset <= scrollbar.scroll_position) { @@ -178,7 +178,7 @@ static void calculate_available_storages(int building_id) continue; } building *store_building = building_get(storage_building_id); - if (store_building && building_is_active(store_building) && store_building->storage_id == i && + if (store_building && building_is_active(store_building) && store_building->extra_attr.storage_id == i && building_storage_resource_max_storable(store_building, data.target_resource_id) > 0) { data.available_storages++; if (b->data.depot.current_order.src_storage_id == store_building->id) { @@ -305,9 +305,9 @@ void window_building_draw_depot_foreground(building_info_context *c) button_border_draw(x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y, depot_order_buttons[1].width, depot_order_buttons[1].height, data.focus_button_id == 2 && data.available_storages > 1); - if (src->storage_id) { + if (src->extra_attr.storage_id) { text_draw_label_and_number_centered(lang_get_string(28, src->type), - src->storage_id, "", x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y + 6, + src->extra_attr.storage_id, "", x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y + 6, depot_order_buttons[1].width, FONT_NORMAL_BLACK, 0); button_border_draw(x_offset + depot_order_buttons[5].x, y_offset + depot_order_buttons[5].y, depot_order_buttons[5].width, depot_order_buttons[5].height, data.focus_button_id == 6); @@ -330,9 +330,9 @@ void window_building_draw_depot_foreground(building_info_context *c) button_border_draw(x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y, depot_order_buttons[2].width, depot_order_buttons[2].height, data.focus_button_id == 3 && data.available_storages > 1); - if (dst->storage_id) { + if (dst->extra_attr.storage_id) { text_draw_label_and_number_centered(lang_get_string(28, dst->type), - dst->storage_id, "", x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y + 6, + dst->extra_attr.storage_id, "", x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y + 6, depot_order_buttons[2].width, FONT_NORMAL_BLACK, 0); button_border_draw(x_offset + depot_order_buttons[6].x, y_offset + depot_order_buttons[6].y, depot_order_buttons[6].width, depot_order_buttons[6].height, data.focus_button_id == 7); @@ -423,7 +423,7 @@ void window_building_draw_depot_select_source_destination(building_info_context c->x_offset + 22 + base_width, y_offset + 50 + ROW_HEIGHT * index, COLOR_FONT_PLAIN, SCALE_NONE); image_draw(assets_lookup_image_id(ASSET_CENTER_CAMERA_ON_BUILDING), c->x_offset + 21 + base_width, y_offset + 49 + ROW_HEIGHT * index, COLOR_MASK_NONE, SCALE_NONE); - text_draw_label_and_number_centered(lang_get_string(28, bld->type), bld->storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, bld->type), bld->extra_attr.storage_id, "", c->x_offset + 32, y_offset + 52 + ROW_HEIGHT * index, base_width, FONT_NORMAL_WHITE, 0); } } diff --git a/src/window/building/distribution.c b/src/window/building/distribution.c index 8c27424c35..b7c1385396 100644 --- a/src/window/building/distribution.c +++ b/src/window/building/distribution.c @@ -208,7 +208,7 @@ static int affect_all_button_distribution_state(void) static int affect_all_button_storage_state(void) { - int storage_id = building_get(data.building_id)->storage_id; + int storage_id = building_get(data.building_id)->extra_attr.storage_id; if (building_storage_check_if_accepts_nothing(storage_id)) { return ACCEPT_ALL; } else { @@ -724,7 +724,7 @@ void window_building_draw_granary(building_info_context *c) c->height_blocks = 24 + y_offset_blocks; outer_panel_draw(c->x_offset, c->y_offset, c->width_blocks, c->height_blocks); - text_draw_label_and_number_centered(lang_get_string(28, b->type), b->storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, b->type), b->extra_attr.storage_id, "", c->x_offset, c->y_offset + 10, 16 * c->width_blocks, FONT_LARGE_BLACK, 0); if (b->has_plague) { @@ -938,7 +938,7 @@ static void draw_resource_orders_buttons(int x, int y, const resource_list *list void window_building_draw_granary_orders_foreground(building_info_context *c) { int y_offset = window_building_get_vertical_offset(c, 28); - const building_storage *storage = building_storage_get(building_get(c->building_id)->storage_id); + const building_storage *storage = building_storage_get(building_get(c->building_id)->extra_attr.storage_id); // empty button button_border_draw(c->x_offset + 80, y_offset + 404, BLOCK_SIZE * (c->width_blocks - 10), 20, data.orders_focus_button_id == 1 ? 1 : 0); @@ -1021,7 +1021,7 @@ void window_building_draw_warehouse(building_info_context *c) c->height_blocks = 24 + y_offset_blocks; outer_panel_draw(c->x_offset, c->y_offset, c->width_blocks, c->height_blocks); - text_draw_label_and_number_centered(lang_get_string(28, b->type), b->storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, b->type), b->extra_attr.storage_id, "", c->x_offset, c->y_offset + 10, 16 * c->width_blocks, FONT_LARGE_BLACK, 0); if (b->has_plague) { @@ -1171,7 +1171,7 @@ void window_building_draw_warehouse_orders_foreground(building_info_context *c) { int y_offset = window_building_get_vertical_offset(c, 28); - const building_storage *storage = building_storage_get(building_get(c->building_id)->storage_id); + const building_storage *storage = building_storage_get(building_get(c->building_id)->extra_attr.storage_id); // emptying button button_border_draw(c->x_offset + 80, y_offset + 404, BLOCK_SIZE * (c->width_blocks - 10), @@ -1348,7 +1348,7 @@ static void toggle_resource_state(int index, int param2) } else { resource = city_resource_get_potential_foods()->items[index]; } - building_storage_cycle_resource_state(b->storage_id, resource); + building_storage_cycle_resource_state(b->extra_attr.storage_id, resource); } window_invalidate(); } @@ -1382,7 +1382,7 @@ static void toggle_partial_resource_state(int index, int param2) } else { resource = city_resource_get_potential_foods()->items[index + scrollbar.scroll_position - 1]; } - building_storage_cycle_partial_resource_state(b->storage_id, resource); + building_storage_cycle_partial_resource_state(b->extra_attr.storage_id, resource); window_invalidate(); } @@ -1404,7 +1404,7 @@ static void dock_toggle_route(int route_id, int param2) static void granary_orders(int index, int param2) { - int storage_id = building_get(data.building_id)->storage_id; + int storage_id = building_get(data.building_id)->extra_attr.storage_id; if (index == 0) { building_storage_toggle_empty_all(storage_id); } else if (index == 1) { @@ -1420,10 +1420,10 @@ static void granary_orders(int index, int param2) static void warehouse_orders(int index, int param2) { if (index == 0) { - int storage_id = building_get(data.building_id)->storage_id; + int storage_id = building_get(data.building_id)->extra_attr.storage_id; building_storage_toggle_empty_all(storage_id); } else if (index == 1) { - int storage_id = building_get(data.building_id)->storage_id; + int storage_id = building_get(data.building_id)->extra_attr.storage_id; if (affect_all_button_storage_state() == ACCEPT_ALL) { building_storage_accept_all(storage_id); } else { diff --git a/src/window/building/figures.c b/src/window/building/figures.c index a25afb7aa1..28a6f6667b 100644 --- a/src/window/building/figures.c +++ b/src/window/building/figures.c @@ -430,12 +430,12 @@ static void draw_depot_cartpusher(building_info_context *c, figure *f) c->x_offset + 40 + width, c->y_offset + 194, COLOR_MASK_NONE, SCALE_NONE); int y_offset = 0; - if (source->storage_id) { + if (source->extra_attr.storage_id) { y_offset = 16; width = text_draw(translation_for(TR_FIGURE_INFO_DEPOT_FROM), c->x_offset + 40, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); width += text_draw_label_and_number(lang_get_string(28, source->type), - source->storage_id, "", + source->extra_attr.storage_id, "", c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); } else { width += image_get(resource_get_data(resource)->image.icon)->original.width; @@ -443,7 +443,7 @@ static void draw_depot_cartpusher(building_info_context *c, figure *f) width += text_draw(translation_for(TR_FIGURE_INFO_DEPOT_TO), c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); text_draw_label_and_number(lang_get_string(28, destination->type), - destination->storage_id, "", + destination->extra_attr.storage_id, "", c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); } From f154f23c60b6e1306a16e850aaf0f165fca7572c Mon Sep 17 00:00:00 2001 From: ZelionD Date: Thu, 16 Jan 2025 17:01:13 -0500 Subject: [PATCH 12/25] fix an issue with storage_id for buildings which are not storage kind --- src/building/building.c | 2 +- src/building/storage.c | 5 +++++ src/building/storage.h | 5 +++++ src/figuretype/trader.c | 2 +- src/widget/city_overlay_other.c | 6 +++--- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index 197dcdea7d..c1adb2c389 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -284,7 +284,7 @@ static void building_delete(building *b) void building_clear_related_data(building *b) { - if (b->extra_attr.storage_id) { + if (is_storage_building(b) && b->extra_attr.storage_id) { building_storage_delete(b->extra_attr.storage_id); b->extra_attr.storage_id = 0; } diff --git a/src/building/storage.c b/src/building/storage.c index e92f27e15d..c9e5e47959 100644 --- a/src/building/storage.c +++ b/src/building/storage.c @@ -72,6 +72,11 @@ void building_storage_reset_building_ids(void) } } +int is_storage_building(const building *b) +{ + return b->type == BUILDING_WAREHOUSE || b->type == BUILDING_GRANARY; +} + int building_storage_create(int building_id) { data_storage *storage; diff --git a/src/building/storage.h b/src/building/storage.h index b3e7bfc527..302462a471 100644 --- a/src/building/storage.h +++ b/src/building/storage.h @@ -66,6 +66,11 @@ typedef struct { */ void building_storage_clear_all(void); +/** + * Checks if building can store goods + */ +int is_storage_building(const building *b); + /** * Creates a building storage * @param building_id The id of the building this is a storage for diff --git a/src/figuretype/trader.c b/src/figuretype/trader.c index 1fda25119c..b446feaebe 100644 --- a/src/figuretype/trader.c +++ b/src/figuretype/trader.c @@ -128,7 +128,7 @@ int figure_trade_caravan_can_buy(figure *trader, int building_id, int city_id) int figure_trade_caravan_can_sell(figure *trader, int building_id, int city_id) { building *b = building_get(building_id); - if (b->type != BUILDING_WAREHOUSE && b->type != BUILDING_GRANARY) { + if (!is_storage_building(b)) { return 0; } if (b->has_plague) { diff --git a/src/widget/city_overlay_other.c b/src/widget/city_overlay_other.c index aa8072a928..5e376cd636 100644 --- a/src/widget/city_overlay_other.c +++ b/src/widget/city_overlay_other.c @@ -116,7 +116,7 @@ static int show_building_logistics(const building *b) static int show_building_storages(const building *b) { b = building_main((building *) b); - return b->extra_attr.storage_id > 0 && building_storage_get(b->extra_attr.storage_id); + return is_storage_building(b) && b->extra_attr.storage_id > 0 && building_storage_get(b->extra_attr.storage_id); } static int show_building_none(const building *b) @@ -915,8 +915,8 @@ static void draw_storage_ids(int x, int y, float scale, int grid_offset) } int building_id = map_building_at(grid_offset); building *b = building_get(building_id); - if (!b || b->is_deleted || map_property_is_deleted(b->grid_offset) || !b->extra_attr.storage_id || - !map_property_is_draw_tile(grid_offset)) { + if (!b || !is_storage_building(b) || b->is_deleted || map_property_is_deleted(b->grid_offset) || + !b->extra_attr.storage_id || !map_property_is_draw_tile(grid_offset)) { return; } uint8_t number[10]; From 990456aff495e5f39415a466585bcffeb9acd65e Mon Sep 17 00:00:00 2001 From: ZelionD Date: Fri, 17 Jan 2025 15:27:44 -0500 Subject: [PATCH 13/25] move advanced sentiment variable to it's own property and bump save file version to 0x9f --- src/building/building.c | 19 ++++++++++++------- src/building/building.h | 27 +++++++++++++++------------ src/building/construction_building.c | 4 ++-- src/building/data_transfer.c | 6 +++--- src/building/granary.c | 16 ++++++++-------- src/building/state.c | 26 ++++++++++++++++++++++++-- src/building/state.h | 5 +++-- src/building/storage.c | 19 +++++++------------ src/building/storage.h | 5 ----- src/building/warehouse.c | 16 ++++++++-------- src/city/sentiment.c | 12 ++++++------ src/figuretype/cartpusher.c | 2 +- src/figuretype/depot.c | 4 ++-- src/figuretype/docker.c | 4 ++-- src/figuretype/trader.c | 8 ++++---- src/game/save_version.h | 3 ++- src/game/undo.c | 2 +- src/platform/augustus.c | 15 ++++++++++++++- src/platform/platform.c | 2 +- src/widget/city_overlay_other.c | 8 ++++---- src/widget/city_without_overlay.c | 2 +- src/window/building/depot.c | 14 +++++++------- src/window/building/distribution.c | 20 ++++++++++---------- src/window/building/figures.c | 6 +++--- 24 files changed, 140 insertions(+), 105 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index c1adb2c389..45d9cb4c60 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -173,17 +173,17 @@ static void remove_adjacent_types(building *b) } void initialize_sentiment_cooldown(building *b) { - if (b->extra_attr.house.sentiment_cooldown_initialized) { + if (b->house_adv_sentiment.cooldown_initialized) { return; } - b->extra_attr.house.sentiment_cooldown_initialized = 1; + b->house_adv_sentiment.cooldown_initialized = 1; if (b->type <= BUILDING_HOUSE_GRAND_INSULA) { - b->extra_attr.house.sentiment_cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; + b->house_adv_sentiment.cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; } else { // Do not apply cooldown to villas - b->extra_attr.house.sentiment_cooldown = 0; + b->house_adv_sentiment.cooldown = 0; } } @@ -284,9 +284,9 @@ static void building_delete(building *b) void building_clear_related_data(building *b) { - if (is_storage_building(b) && b->extra_attr.storage_id) { - building_storage_delete(b->extra_attr.storage_id); - b->extra_attr.storage_id = 0; + if (building_is_storage_kind(b->type) && b->storage_id) { + building_storage_delete(b->storage_id); + b->storage_id = 0; } if (b->type == BUILDING_FORT) { formation_legion_delete_for_fort(b); @@ -440,6 +440,11 @@ int building_is_house(building_type type) return type >= BUILDING_HOUSE_VACANT_LOT && type <= BUILDING_HOUSE_LUXURY_PALACE; } +int building_is_storage_kind(building_type type) +{ + return type == BUILDING_WAREHOUSE || type == BUILDING_GRANARY; +} + // For Venus GT base bonus int building_is_statue_garden_temple(building_type type) { diff --git a/src/building/building.h b/src/building/building.h index a241214614..36b92b7861 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -183,22 +183,20 @@ typedef struct building { signed char desirability; unsigned char is_deleted; unsigned char is_adjacent_to_water; - union { - unsigned char storage_id; - // New advanced sentiment contribution logic requires cooldown for newly built houses. - // The new happiness gain/drop logic will not be applied until cooldown expires. - // Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total. - // That should be enough to build new housing block and evolve it. - struct { - uint8_t sentiment_cooldown_initialized: 1; - uint8_t sentiment_cooldown: 3; - uint8_t reserved: 4; - } house; - } extra_attr; + unsigned char storage_id; union { signed char house_happiness; signed char native_anger; } sentiment; + // New advanced sentiment contribution logic requires cooldown for newly built houses. + // The new happiness gain/drop logic will not be applied until cooldown expires. + // Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total. + // That should be enough to build new housing block and evolve it. + struct { + uint8_t cooldown_initialized: 1; + uint8_t cooldown: 3; + uint8_t reserved: 4; + } house_adv_sentiment; unsigned char show_on_problem_overlay; unsigned char house_tavern_wine_access; unsigned char house_tavern_food_access; @@ -253,6 +251,11 @@ void building_update_state(void); void building_update_desirability(void); +/** + * Checks if building can store goods + */ +int building_is_storage_kind(building_type type); + int building_is_house(building_type type); int building_is_ceres_temple(building_type type); diff --git a/src/building/construction_building.c b/src/building/construction_building.c index a9460b6e4d..448da773d4 100644 --- a/src/building/construction_building.c +++ b/src/building/construction_building.c @@ -106,7 +106,7 @@ static void add_warehouse(building *b) int y_offset[9] = { 0, 1, 0, 1, 2, 0, 2, 1, 2 }; int corner = building_rotation_get_corner(2 * building_rotation_get_rotation()); - b->extra_attr.storage_id = building_storage_create(b->id); + b->storage_id = building_storage_create(b->id); b->prev_part_building_id = 0; map_building_tiles_add(b->id, b->x + x_offset[corner], b->y + y_offset[corner], 1, image_group(GROUP_BUILDING_WAREHOUSE), TERRAIN_BUILDING); @@ -145,7 +145,7 @@ static void add_depot(building *b) static void add_granary(building *b) { - b->extra_attr.storage_id = building_storage_create(b->id); + b->storage_id = building_storage_create(b->id); add_building(b); map_tiles_update_area_roads(b->x, b->y, 5); } diff --git a/src/building/data_transfer.c b/src/building/data_transfer.c index f22803e4f4..14216991bf 100644 --- a/src/building/data_transfer.c +++ b/src/building/data_transfer.c @@ -51,11 +51,11 @@ int building_data_transfer_copy(building *b) memcpy(data.resource, b->accepted_goods, sizeof(unsigned char) * RESOURCE_MAX); break; case DATA_TYPE_GRANARY: - storage = building_storage_get(b->extra_attr.storage_id); + storage = building_storage_get(b->storage_id); data.storage = *storage; break; case DATA_TYPE_WAREHOUSE: - storage = building_storage_get(b->extra_attr.storage_id); + storage = building_storage_get(b->storage_id); data.storage = *storage; break; case DATA_TYPE_DOCK: @@ -94,7 +94,7 @@ int building_data_transfer_paste(building *b) break; case DATA_TYPE_GRANARY: case DATA_TYPE_WAREHOUSE: - building_storage_set_data(b->extra_attr.storage_id, data.storage); + building_storage_set_data(b->storage_id, data.storage); break; case DATA_TYPE_DOCK: memcpy(b->accepted_goods, data.resource, sizeof(unsigned char) * RESOURCE_MAX); diff --git a/src/building/granary.c b/src/building/granary.c index 695a3f2353..39ea13da5f 100644 --- a/src/building/granary.c +++ b/src/building/granary.c @@ -41,7 +41,7 @@ static int get_amount(building *granary, int resource) static int granary_is_accepting(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int amount = get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_ACCEPTING) || @@ -56,7 +56,7 @@ static int granary_is_accepting(int resource, building *b) int building_granary_is_getting(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int amount = get_amount(b, resource); return !b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || @@ -67,7 +67,7 @@ int building_granary_is_getting(int resource, building *b) static int granary_is_gettable(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); return !b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || (s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING_3QUARTERS) || @@ -286,7 +286,7 @@ int building_granary_maximum_receptible_amount(int resource, building *b) } int stored_amount = b->resources[resource]; int max_amount; - switch (building_storage_get(b->extra_attr.storage_id)->resource_state[resource]) { + switch (building_storage_get(b->storage_id)->resource_state[resource]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: max_amount = FULL_GRANARY; @@ -350,7 +350,7 @@ int building_granary_determine_worker_task(building *granary) if (pct_workers < 50) { return GRANARY_TASK_NONE; } - const building_storage *s = building_storage_get(granary->extra_attr.storage_id); + const building_storage *s = building_storage_get(granary->storage_id); if (s->empty_all) { // bring food to another granary for (int i = RESOURCE_MIN_FOOD; i < RESOURCE_MAX_FOOD; i++) { @@ -418,7 +418,7 @@ int building_granary_accepts_storage(building *b, int resource, int *understaffe } return 0; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (building_granary_is_not_accepting(resource, b) || s->empty_all) { return 0; } @@ -488,7 +488,7 @@ int building_getting_granary_for_storing(int x, int y, int resource, int road_ne if (pct_workers < 100) { continue; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (!building_granary_is_getting(resource, b) || s->empty_all) { continue; } @@ -520,7 +520,7 @@ int building_granary_amount_can_get_from(building *destination, building *origin int building_granary_for_getting(building *src, map_point *dst, int min_amount) { - const building_storage *s_src = building_storage_get(src->extra_attr.storage_id); + const building_storage *s_src = building_storage_get(src->storage_id); if (s_src->empty_all) { return 0; } diff --git a/src/building/state.c b/src/building/state.c index f4dcf97e2f..95854da680 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -1,5 +1,7 @@ #include "state.h" +#include + #include "building/industry.h" #include "building/monument.h" #include "building/roadblock.h" @@ -162,8 +164,16 @@ void building_state_save_to_buffer(buffer *buf, const building *b) buffer_write_i8(buf, b->desirability); buffer_write_u8(buf, b->is_deleted); buffer_write_u8(buf, b->is_adjacent_to_water); - buffer_write_u8(buf, b->extra_attr.storage_id); // which union field we use does not matter + buffer_write_u8(buf, b->storage_id); buffer_write_i8(buf, b->sentiment.house_happiness); // which union field we use does not matter + + assert (sizeof(b->house_adv_sentiment) == sizeof(uint8_t)); + if (building_is_house(b->type)) { + buffer_write_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment)); + } else { + buffer_skip(buf, sizeof(b->house_adv_sentiment)); + } + buffer_write_u8(buf, b->show_on_problem_overlay); // expanded building data @@ -486,7 +496,19 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->desirability = buffer_read_i8(buf); b->is_deleted = buffer_read_u8(buf); b->is_adjacent_to_water = buffer_read_u8(buf); - b->extra_attr.storage_id = buffer_read_u8(buf); // which union field we use does not matter + if (building_is_storage_kind(b->type)) { + b->storage_id = buffer_read_u8(buf); + } else { + b->storage_id = 0; + buffer_skip(buf, 1); // do not load storage_id for non-storage buildings + } + if (save_version >= SAVE_GAME_LAST_ADVANCED_SENTIMENT) { + if (building_is_house(b->type)) { + buffer_read_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment)); + } else { + buffer_skip(buf, sizeof(b->house_adv_sentiment)); + } + } b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter b->show_on_problem_overlay = buffer_read_u8(buf); diff --git a/src/building/state.h b/src/building/state.h index b7f466a6a1..684a56009b 100644 --- a/src/building/state.h +++ b/src/building/state.h @@ -11,8 +11,9 @@ #define BUILDING_STATE_TOURISM_BUFFER_SIZE (BUILDING_STATE_ORIGINAL_BUFFER_SIZE + 6) // 134 #define BUILDING_STATE_VARIANTS_AND_UPGRADES (BUILDING_STATE_TOURISM_BUFFER_SIZE + 2) // 136 #define BUILDING_STATE_STRIKES (BUILDING_STATE_VARIANTS_AND_UPGRADES + 1) // 137 -#define BUILDING_STATE_SICKNESS (BUILDING_STATE_STRIKES + 5) // 142 -#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 126 (plus variable resource size) +#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + 1) // 138 +#define BUILDING_STATE_SICKNESS (BUILDING_STATE_ADV_SENTIMENT + 5) // 143 +#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 127 (plus variable resource size) #define BUILDING_STATE_DYNAMIC_RESOURCES (BUILDING_STATE_WITHOUT_RESOURCES + BUILDING_STATE_NONSTATIC_RESOURCE_SIZE) #define BUILDING_STATE_CURRENT_BUFFER_SIZE (BUILDING_STATE_DYNAMIC_RESOURCES + 8) diff --git a/src/building/storage.c b/src/building/storage.c index c9e5e47959..e20279593e 100644 --- a/src/building/storage.c +++ b/src/building/storage.c @@ -60,23 +60,18 @@ void building_storage_reset_building_ids(void) if (b->state == BUILDING_STATE_UNUSED) { continue; } - if (b->extra_attr.storage_id) { - if (array_item(storages, b->extra_attr.storage_id)->building_id) { + if (b->storage_id) { + if (array_item(storages, b->storage_id)->building_id) { // storage is already connected to a building: corrupt, create new - b->extra_attr.storage_id = building_storage_create(b->id); + b->storage_id = building_storage_create(b->id); } else { - array_item(storages, b->extra_attr.storage_id)->building_id = b->id; + array_item(storages, b->storage_id)->building_id = b->id; } } } } } -int is_storage_building(const building *b) -{ - return b->type == BUILDING_WAREHOUSE || b->type == BUILDING_GRANARY; -} - int building_storage_create(int building_id) { data_storage *storage; @@ -165,12 +160,12 @@ void building_storage_cycle_resource_state(int storage_id, resource_type resourc void building_storage_set_permission(building_storage_permission_states p, building *b) { int permission_bit = 1 << p; - array_item(storages, b->extra_attr.storage_id)->storage.permissions ^= permission_bit; + array_item(storages, b->storage_id)->storage.permissions ^= permission_bit; } int building_storage_get_permission(building_storage_permission_states p, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int permission_bit = 1 << p; return !(s->permissions & permission_bit); } @@ -234,7 +229,7 @@ int building_storage_resource_max_storable(building *b, resource_type resource_i return 0; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); switch (s->resource_state[resource_id]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: diff --git a/src/building/storage.h b/src/building/storage.h index 302462a471..b3e7bfc527 100644 --- a/src/building/storage.h +++ b/src/building/storage.h @@ -66,11 +66,6 @@ typedef struct { */ void building_storage_clear_all(void); -/** - * Checks if building can store goods - */ -int is_storage_building(const building *b); - /** * Creates a building storage * @param building_id The id of the building this is a storage for diff --git a/src/building/warehouse.c b/src/building/warehouse.c index 0c4343ebb5..53cd56ec28 100644 --- a/src/building/warehouse.c +++ b/src/building/warehouse.c @@ -275,7 +275,7 @@ static building *get_next_warehouse(void) int building_warehouse_is_accepting(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int amount = building_warehouse_get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_ACCEPTING) || @@ -290,7 +290,7 @@ int building_warehouse_is_accepting(int resource, building *b) int building_warehouse_is_getting(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int amount = building_warehouse_get_amount(b, resource); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || @@ -305,7 +305,7 @@ int building_warehouse_is_getting(int resource, building *b) static int warehouse_is_gettable(int resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (!b->has_plague && ((s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING) || (s->resource_state[resource] == BUILDING_STORAGE_STATE_GETTING_HALF) || @@ -324,7 +324,7 @@ int building_warehouse_is_not_accepting(int resource, building *b) static int get_acceptable_quantity(resource_type resource, building *b) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); switch (s->resource_state[resource]) { case BUILDING_STORAGE_STATE_ACCEPTING: case BUILDING_STORAGE_STATE_GETTING: @@ -476,7 +476,7 @@ int building_warehouse_accepts_storage(building *b, int resource, int *understaf !b->has_road_access || b->distance_from_entry <= 0 || b->has_plague) { return 0; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (building_warehouse_is_not_accepting(resource, b) || s->empty_all) { return 0; } @@ -628,7 +628,7 @@ static int determine_granary_accept_foods(int resources[RESOURCE_MAX_FOOD], int } int pct_workers = calc_percentage(b->num_workers, model_get_building(b->type)->laborers); if (pct_workers >= 100 && b->resources[RESOURCE_NONE] >= 100) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (!s->empty_all) { for (int r = 0; r < RESOURCE_MAX_FOOD; r++) { if (!building_granary_is_not_accepting(r, b)) { @@ -657,7 +657,7 @@ static int determine_granary_get_foods(int resources[RESOURCE_MAX_FOOD], int roa } int pct_workers = calc_percentage(b->num_workers, model_get_building(b->type)->laborers); if (pct_workers >= 100 && b->resources[RESOURCE_NONE] > 100) { - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); if (!s->empty_all) { for (int r = 0; r < RESOURCE_MAX_FOOD; r++) { if (building_granary_is_getting(r, b)) { @@ -692,7 +692,7 @@ int building_warehouse_determine_worker_task(building *warehouse, int *resource) if (pct_workers < 50) { return WAREHOUSE_TASK_NONE; } - const building_storage *s = building_storage_get(warehouse->extra_attr.storage_id); + const building_storage *s = building_storage_get(warehouse->storage_id); building *space; // get resources for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 2f010dfc08..97781b1a6d 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -339,26 +339,26 @@ const int advanced_sentiment_drop_modifier[5] = { // Checks if house building still has a cooldown before apply advanced sentiment change logic int is_house_has_ongoing_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { - if (!building_is_house(b->type) || !b->extra_attr.house.sentiment_cooldown_initialized) { + if (!building_is_house(b->type) || !b->house_adv_sentiment.cooldown_initialized) { return 0; } if (b->type > BUILDING_HOUSE_GRAND_INSULA) { // Reset cooldown for villas - b->extra_attr.house.sentiment_cooldown = 0; - } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->extra_attr.house.sentiment_cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { + b->house_adv_sentiment.cooldown = 0; + } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->house_adv_sentiment.cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { // Wait for new citizens to arrive return 1; } if (update_sentiment_cooldown && - b->extra_attr.house.sentiment_cooldown && + b->house_adv_sentiment.cooldown && game_time_month() % ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS == 0) { // Decrease tick once configured amount of game months has passed. - b->extra_attr.house.sentiment_cooldown--; + b->house_adv_sentiment.cooldown--; } - if (!b->extra_attr.house.sentiment_cooldown) { + if (!b->house_adv_sentiment.cooldown) { // Cooldown has ended return 0; } diff --git a/src/figuretype/cartpusher.c b/src/figuretype/cartpusher.c index d1f8a3f61c..1a818e7119 100644 --- a/src/figuretype/cartpusher.c +++ b/src/figuretype/cartpusher.c @@ -676,7 +676,7 @@ static void determine_warehouseman_destination(figure *f, int road_network_id, i } // priority 5: another warehouse to empty this one - if (building_storage_get(building_get(f->building_id)->extra_attr.storage_id)->empty_all) { + if (building_storage_get(building_get(f->building_id)->storage_id)->empty_all) { dst_building_id = building_warehouse_for_storing(f->building_id, f->x, f->y, f->resource_id, -1, 0, &dst); // deliver to another warehouse because this one is being emptied diff --git a/src/figuretype/depot.c b/src/figuretype/depot.c index bc76d6ba4d..bf42d80445 100644 --- a/src/figuretype/depot.c +++ b/src/figuretype/depot.c @@ -209,7 +209,7 @@ static int check_valid_storages(order *current_order, int action_state) { int valid_storages = 1; building *src = building_get(current_order->src_storage_id); - if (!src || !src->extra_attr.storage_id || src->state != BUILDING_STATE_IN_USE) { + if (!src || !src->storage_id || src->state != BUILDING_STATE_IN_USE) { if (action_state == FIGURE_ACTION_239_DEPOT_CART_PUSHER_HEADING_TO_SOURCE || action_state == FIGURE_ACTION_240_DEPOT_CART_PUSHER_AT_SOURCE) { valid_storages = 0; @@ -217,7 +217,7 @@ static int check_valid_storages(order *current_order, int action_state) current_order->src_storage_id = 0; } building *dst = building_get(current_order->dst_storage_id); - if (!dst || !dst->extra_attr.storage_id || dst->state != BUILDING_STATE_IN_USE) { + if (!dst || !dst->storage_id || dst->state != BUILDING_STATE_IN_USE) { valid_storages = 0; current_order->dst_storage_id = 0; } diff --git a/src/figuretype/docker.c b/src/figuretype/docker.c index 3bb1dcaefd..32df83b6cf 100644 --- a/src/figuretype/docker.c +++ b/src/figuretype/docker.c @@ -160,7 +160,7 @@ static int get_closest_building_for_import(int x, int y, int city_id, building * int min_building_id = 0; for (building *b = building_first_of_type(BUILDING_WAREHOUSE); b; b = b->next_of_type) { if (is_invalid_destination(b, dock) || - building_storage_get(b->extra_attr.storage_id)->empty_all || + building_storage_get(b->storage_id)->empty_all || building_warehouse_is_not_accepting(resource, b)) { continue; } @@ -189,7 +189,7 @@ static int get_closest_building_for_import(int x, int y, int city_id, building * if (resource_is_food(resource)) { for (building *b = building_first_of_type(BUILDING_GRANARY); b; b = b->next_of_type) { if (is_invalid_destination(b, dock) || - building_storage_get(b->extra_attr.storage_id)->empty_all || + building_storage_get(b->storage_id)->empty_all || building_granary_is_not_accepting(resource, b) || building_granary_is_full(b)) { continue; diff --git a/src/figuretype/trader.c b/src/figuretype/trader.c index b446feaebe..7b95ac0781 100644 --- a/src/figuretype/trader.c +++ b/src/figuretype/trader.c @@ -128,7 +128,7 @@ int figure_trade_caravan_can_buy(figure *trader, int building_id, int city_id) int figure_trade_caravan_can_sell(figure *trader, int building_id, int city_id) { building *b = building_get(building_id); - if (!is_storage_building(b)) { + if (!building_is_storage_kind(b->type)) { return 0; } if (b->has_plague) { @@ -140,7 +140,7 @@ int figure_trade_caravan_can_sell(figure *trader, int building_id, int city_id) if (!building_storage_get_permission(BUILDING_STORAGE_PERMISSION_TRADERS, b)) { return 0; } - if (building_storage_get(b->extra_attr.storage_id)->empty_all) { + if (building_storage_get(b->storage_id)->empty_all) { return 0; } if (b->type == BUILDING_GRANARY) { @@ -347,7 +347,7 @@ static int get_closest_storage(const figure *f, int x, int y, int city_id, map_p !building_storage_get_permission(BUILDING_STORAGE_PERMISSION_TRADERS, b)) { continue; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int distance_penalty = 32; int num_imports_for_warehouse = 0; for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { @@ -394,7 +394,7 @@ static int get_closest_storage(const figure *f, int x, int y, int city_id, map_p continue; } - const building_storage *s = building_storage_get(b->extra_attr.storage_id); + const building_storage *s = building_storage_get(b->storage_id); int distance_penalty = 32; for (int r = RESOURCE_MIN; r < RESOURCE_MAX; r++) { int resource = city_trade_next_caravan_import_resource(); diff --git a/src/game/save_version.h b/src/game/save_version.h index df03c462e6..36c3a153ca 100644 --- a/src/game/save_version.h +++ b/src/game/save_version.h @@ -2,7 +2,7 @@ #define GAME_SAVE_VERSION_H typedef enum { - SAVE_GAME_CURRENT_VERSION = 0x9e, + SAVE_GAME_CURRENT_VERSION = 0x9f, SAVE_GAME_LAST_ORIGINAL_LIMITS_VERSION = 0x66, SAVE_GAME_LAST_SMALLER_IMAGE_ID_VERSION = 0x76, @@ -41,6 +41,7 @@ typedef enum { SAVE_GAME_LAST_WRONG_SCENARIO_END_OFFSET = 0x9b, SAVE_GAME_LAST_NO_CUSTOM_EMPIRE_MAP_IMAGE = 0x9c, SAVE_GAME_LAST_NO_CUSTOM_CAMPAIGNS = 0x9d, + SAVE_GAME_LAST_ADVANCED_SENTIMENT = 0x9f, } savegame_version_t; typedef enum { diff --git a/src/game/undo.c b/src/game/undo.c index 056dde12df..be0743478b 100644 --- a/src/game/undo.c +++ b/src/game/undo.c @@ -222,7 +222,7 @@ void game_undo_perform(void) break; case BUILDING_WAREHOUSE: case BUILDING_GRANARY: - if (!building_storage_restore(b->extra_attr.storage_id)) { + if (!building_storage_restore(b->storage_id)) { building_storage_reset_building_ids(); } break; diff --git a/src/platform/augustus.c b/src/platform/augustus.c index cc9d9246bc..d55c36ee8b 100644 --- a/src/platform/augustus.c +++ b/src/platform/augustus.c @@ -1,3 +1,6 @@ +#if (defined(_WIN32) || defined(_WIN64)) && !defined(_MSC_VER) +#define SDL_MAIN_HANDLED +#endif #include "SDL.h" #include "core/config.h" @@ -39,7 +42,7 @@ #include #ifdef _MSC_VER -#include +#include #endif #if defined(USE_TINYFILEDIALOGS) || defined(__ANDROID__) || defined(__IPHONEOS__) @@ -694,7 +697,17 @@ static void setup(const augustus_args *args) data.active = 1; } +#if (defined(_WIN32) || defined(_WIN64)) && !defined(_MSC_VER) +extern int __argc; +extern char ** __argv; +int main() { + SDL_SetMainReady(); + return SDL_main(__argc, __argv); +} +int SDL_main(int argc, char **argv) +#else int main(int argc, char **argv) +#endif { augustus_args args; if (!platform_parse_arguments(argc, argv, &args)) { diff --git a/src/platform/platform.c b/src/platform/platform.c index c8c51b231c..35c0358b61 100644 --- a/src/platform/platform.c +++ b/src/platform/platform.c @@ -58,7 +58,7 @@ const char *system_architecture(void) } #if defined(_WIN32) || defined(_WIN64) -#include +#include #elif defined (__GNUC__) && !defined (__SWITCH__) #include #endif diff --git a/src/widget/city_overlay_other.c b/src/widget/city_overlay_other.c index 5e376cd636..7ce348d2ef 100644 --- a/src/widget/city_overlay_other.c +++ b/src/widget/city_overlay_other.c @@ -116,7 +116,7 @@ static int show_building_logistics(const building *b) static int show_building_storages(const building *b) { b = building_main((building *) b); - return is_storage_building(b) && b->extra_attr.storage_id > 0 && building_storage_get(b->extra_attr.storage_id); + return building_is_storage_kind(b->type) && b->storage_id > 0 && building_storage_get(b->storage_id); } static int show_building_none(const building *b) @@ -915,12 +915,12 @@ static void draw_storage_ids(int x, int y, float scale, int grid_offset) } int building_id = map_building_at(grid_offset); building *b = building_get(building_id); - if (!b || !is_storage_building(b) || b->is_deleted || map_property_is_deleted(b->grid_offset) || - !b->extra_attr.storage_id || !map_property_is_draw_tile(grid_offset)) { + if (!b || !building_is_storage_kind(b->type) || b->is_deleted || map_property_is_deleted(b->grid_offset) || + !b->storage_id || !map_property_is_draw_tile(grid_offset)) { return; } uint8_t number[10]; - string_from_int(number, b->extra_attr.storage_id, 0); + string_from_int(number, b->storage_id, 0); int text_width = text_get_width(number, FONT_SMALL_PLAIN); int box_width = text_width + 10; int box_height = 22; diff --git a/src/widget/city_without_overlay.c b/src/widget/city_without_overlay.c index 91d904e58a..5b4957cba5 100644 --- a/src/widget/city_without_overlay.c +++ b/src/widget/city_without_overlay.c @@ -592,7 +592,7 @@ static void draw_permissions_flag(building *b, int x, int y, color_t color_mask) base_permission_image[6] = assets_get_image_id("UI", "Warehouse_Flag_Land_Sea"); base_permission_image[7] = assets_get_image_id("UI", "Warehouse_Flag_All"); } - const building_storage *storage = building_storage_get(b->extra_attr.storage_id); + const building_storage *storage = building_storage_get(b->storage_id); int flag_permission_mask = 0x7; int permissions = (~storage->permissions) & flag_permission_mask; if (!permissions) { diff --git a/src/window/building/depot.c b/src/window/building/depot.c index c3fbd68868..764394f224 100644 --- a/src/window/building/depot.c +++ b/src/window/building/depot.c @@ -145,7 +145,7 @@ static void setup_buttons_for_selected_depot(void) continue; } building *store_building = building_get(storage->building_id); - if (building_is_active(store_building) && store_building->extra_attr.storage_id == storage->id && + if (building_is_active(store_building) && store_building->storage_id == storage->id && building_storage_resource_max_storable(store_building, data.target_resource_id) > 0) { current_storage_offset++; if (current_storage_offset <= scrollbar.scroll_position) { @@ -178,7 +178,7 @@ static void calculate_available_storages(int building_id) continue; } building *store_building = building_get(storage_building_id); - if (store_building && building_is_active(store_building) && store_building->extra_attr.storage_id == i && + if (store_building && building_is_active(store_building) && store_building->storage_id == i && building_storage_resource_max_storable(store_building, data.target_resource_id) > 0) { data.available_storages++; if (b->data.depot.current_order.src_storage_id == store_building->id) { @@ -305,9 +305,9 @@ void window_building_draw_depot_foreground(building_info_context *c) button_border_draw(x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y, depot_order_buttons[1].width, depot_order_buttons[1].height, data.focus_button_id == 2 && data.available_storages > 1); - if (src->extra_attr.storage_id) { + if (src->storage_id) { text_draw_label_and_number_centered(lang_get_string(28, src->type), - src->extra_attr.storage_id, "", x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y + 6, + src->storage_id, "", x_offset + depot_order_buttons[1].x, y_offset + depot_order_buttons[1].y + 6, depot_order_buttons[1].width, FONT_NORMAL_BLACK, 0); button_border_draw(x_offset + depot_order_buttons[5].x, y_offset + depot_order_buttons[5].y, depot_order_buttons[5].width, depot_order_buttons[5].height, data.focus_button_id == 6); @@ -330,9 +330,9 @@ void window_building_draw_depot_foreground(building_info_context *c) button_border_draw(x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y, depot_order_buttons[2].width, depot_order_buttons[2].height, data.focus_button_id == 3 && data.available_storages > 1); - if (dst->extra_attr.storage_id) { + if (dst->storage_id) { text_draw_label_and_number_centered(lang_get_string(28, dst->type), - dst->extra_attr.storage_id, "", x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y + 6, + dst->storage_id, "", x_offset + depot_order_buttons[2].x, y_offset + depot_order_buttons[2].y + 6, depot_order_buttons[2].width, FONT_NORMAL_BLACK, 0); button_border_draw(x_offset + depot_order_buttons[6].x, y_offset + depot_order_buttons[6].y, depot_order_buttons[6].width, depot_order_buttons[6].height, data.focus_button_id == 7); @@ -423,7 +423,7 @@ void window_building_draw_depot_select_source_destination(building_info_context c->x_offset + 22 + base_width, y_offset + 50 + ROW_HEIGHT * index, COLOR_FONT_PLAIN, SCALE_NONE); image_draw(assets_lookup_image_id(ASSET_CENTER_CAMERA_ON_BUILDING), c->x_offset + 21 + base_width, y_offset + 49 + ROW_HEIGHT * index, COLOR_MASK_NONE, SCALE_NONE); - text_draw_label_and_number_centered(lang_get_string(28, bld->type), bld->extra_attr.storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, bld->type), bld->storage_id, "", c->x_offset + 32, y_offset + 52 + ROW_HEIGHT * index, base_width, FONT_NORMAL_WHITE, 0); } } diff --git a/src/window/building/distribution.c b/src/window/building/distribution.c index b7c1385396..8c27424c35 100644 --- a/src/window/building/distribution.c +++ b/src/window/building/distribution.c @@ -208,7 +208,7 @@ static int affect_all_button_distribution_state(void) static int affect_all_button_storage_state(void) { - int storage_id = building_get(data.building_id)->extra_attr.storage_id; + int storage_id = building_get(data.building_id)->storage_id; if (building_storage_check_if_accepts_nothing(storage_id)) { return ACCEPT_ALL; } else { @@ -724,7 +724,7 @@ void window_building_draw_granary(building_info_context *c) c->height_blocks = 24 + y_offset_blocks; outer_panel_draw(c->x_offset, c->y_offset, c->width_blocks, c->height_blocks); - text_draw_label_and_number_centered(lang_get_string(28, b->type), b->extra_attr.storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, b->type), b->storage_id, "", c->x_offset, c->y_offset + 10, 16 * c->width_blocks, FONT_LARGE_BLACK, 0); if (b->has_plague) { @@ -938,7 +938,7 @@ static void draw_resource_orders_buttons(int x, int y, const resource_list *list void window_building_draw_granary_orders_foreground(building_info_context *c) { int y_offset = window_building_get_vertical_offset(c, 28); - const building_storage *storage = building_storage_get(building_get(c->building_id)->extra_attr.storage_id); + const building_storage *storage = building_storage_get(building_get(c->building_id)->storage_id); // empty button button_border_draw(c->x_offset + 80, y_offset + 404, BLOCK_SIZE * (c->width_blocks - 10), 20, data.orders_focus_button_id == 1 ? 1 : 0); @@ -1021,7 +1021,7 @@ void window_building_draw_warehouse(building_info_context *c) c->height_blocks = 24 + y_offset_blocks; outer_panel_draw(c->x_offset, c->y_offset, c->width_blocks, c->height_blocks); - text_draw_label_and_number_centered(lang_get_string(28, b->type), b->extra_attr.storage_id, "", + text_draw_label_and_number_centered(lang_get_string(28, b->type), b->storage_id, "", c->x_offset, c->y_offset + 10, 16 * c->width_blocks, FONT_LARGE_BLACK, 0); if (b->has_plague) { @@ -1171,7 +1171,7 @@ void window_building_draw_warehouse_orders_foreground(building_info_context *c) { int y_offset = window_building_get_vertical_offset(c, 28); - const building_storage *storage = building_storage_get(building_get(c->building_id)->extra_attr.storage_id); + const building_storage *storage = building_storage_get(building_get(c->building_id)->storage_id); // emptying button button_border_draw(c->x_offset + 80, y_offset + 404, BLOCK_SIZE * (c->width_blocks - 10), @@ -1348,7 +1348,7 @@ static void toggle_resource_state(int index, int param2) } else { resource = city_resource_get_potential_foods()->items[index]; } - building_storage_cycle_resource_state(b->extra_attr.storage_id, resource); + building_storage_cycle_resource_state(b->storage_id, resource); } window_invalidate(); } @@ -1382,7 +1382,7 @@ static void toggle_partial_resource_state(int index, int param2) } else { resource = city_resource_get_potential_foods()->items[index + scrollbar.scroll_position - 1]; } - building_storage_cycle_partial_resource_state(b->extra_attr.storage_id, resource); + building_storage_cycle_partial_resource_state(b->storage_id, resource); window_invalidate(); } @@ -1404,7 +1404,7 @@ static void dock_toggle_route(int route_id, int param2) static void granary_orders(int index, int param2) { - int storage_id = building_get(data.building_id)->extra_attr.storage_id; + int storage_id = building_get(data.building_id)->storage_id; if (index == 0) { building_storage_toggle_empty_all(storage_id); } else if (index == 1) { @@ -1420,10 +1420,10 @@ static void granary_orders(int index, int param2) static void warehouse_orders(int index, int param2) { if (index == 0) { - int storage_id = building_get(data.building_id)->extra_attr.storage_id; + int storage_id = building_get(data.building_id)->storage_id; building_storage_toggle_empty_all(storage_id); } else if (index == 1) { - int storage_id = building_get(data.building_id)->extra_attr.storage_id; + int storage_id = building_get(data.building_id)->storage_id; if (affect_all_button_storage_state() == ACCEPT_ALL) { building_storage_accept_all(storage_id); } else { diff --git a/src/window/building/figures.c b/src/window/building/figures.c index 28a6f6667b..a25afb7aa1 100644 --- a/src/window/building/figures.c +++ b/src/window/building/figures.c @@ -430,12 +430,12 @@ static void draw_depot_cartpusher(building_info_context *c, figure *f) c->x_offset + 40 + width, c->y_offset + 194, COLOR_MASK_NONE, SCALE_NONE); int y_offset = 0; - if (source->extra_attr.storage_id) { + if (source->storage_id) { y_offset = 16; width = text_draw(translation_for(TR_FIGURE_INFO_DEPOT_FROM), c->x_offset + 40, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); width += text_draw_label_and_number(lang_get_string(28, source->type), - source->extra_attr.storage_id, "", + source->storage_id, "", c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); } else { width += image_get(resource_get_data(resource)->image.icon)->original.width; @@ -443,7 +443,7 @@ static void draw_depot_cartpusher(building_info_context *c, figure *f) width += text_draw(translation_for(TR_FIGURE_INFO_DEPOT_TO), c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); text_draw_label_and_number(lang_get_string(28, destination->type), - destination->extra_attr.storage_id, "", + destination->storage_id, "", c->x_offset + 40 + width, c->y_offset + 200 + y_offset, FONT_NORMAL_BROWN, 0); } From a45a2f89abb61b6dfd5488c75aee8fe2c657cfab Mon Sep 17 00:00:00 2001 From: ZelionD Date: Fri, 17 Jan 2025 15:35:05 -0500 Subject: [PATCH 14/25] revert cross-compilation changes accidentally commited --- src/platform/augustus.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/platform/augustus.c b/src/platform/augustus.c index d55c36ee8b..25473b5694 100644 --- a/src/platform/augustus.c +++ b/src/platform/augustus.c @@ -1,6 +1,3 @@ -#if (defined(_WIN32) || defined(_WIN64)) && !defined(_MSC_VER) -#define SDL_MAIN_HANDLED -#endif #include "SDL.h" #include "core/config.h" @@ -697,17 +694,7 @@ static void setup(const augustus_args *args) data.active = 1; } -#if (defined(_WIN32) || defined(_WIN64)) && !defined(_MSC_VER) -extern int __argc; -extern char ** __argv; -int main() { - SDL_SetMainReady(); - return SDL_main(__argc, __argv); -} -int SDL_main(int argc, char **argv) -#else int main(int argc, char **argv) -#endif { augustus_args args; if (!platform_parse_arguments(argc, argv, &args)) { From 58eebdf65354868e748998df8fb21612f9cecb66 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 21 Jan 2025 12:20:09 -0500 Subject: [PATCH 15/25] fix load order from file --- src/building/state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/building/state.c b/src/building/state.c index 95854da680..0663c13d70 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -502,6 +502,7 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->storage_id = 0; buffer_skip(buf, 1); // do not load storage_id for non-storage buildings } + b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter if (save_version >= SAVE_GAME_LAST_ADVANCED_SENTIMENT) { if (building_is_house(b->type)) { buffer_read_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment)); @@ -509,7 +510,6 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ buffer_skip(buf, sizeof(b->house_adv_sentiment)); } } - b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter b->show_on_problem_overlay = buffer_read_u8(buf); // Wharves produce fish and don't need any progress From 59c1c306b77dcc257ed5f1716b5814671a37ae82 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 21 Jan 2025 12:42:36 -0500 Subject: [PATCH 16/25] name struct advanced_sentiment --- src/building/building.h | 12 +++++++----- src/building/state.h | 2 +- src/city/sentiment.c | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/building/building.h b/src/building/building.h index 36b92b7861..b07b82e76f 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -22,6 +22,12 @@ typedef enum order_condition_type { ORDER_CONDITION_DESTINATION_HAS_LESS_THAN } order_condition_type; +typedef struct advanced_sentiment { + uint8_t cooldown_initialized: 1; + uint8_t cooldown: 3; + uint8_t reserved: 4; +} advanced_sentiment; + typedef struct order { resource_type resource_type; int src_storage_id; @@ -192,11 +198,7 @@ typedef struct building { // The new happiness gain/drop logic will not be applied until cooldown expires. // Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total. // That should be enough to build new housing block and evolve it. - struct { - uint8_t cooldown_initialized: 1; - uint8_t cooldown: 3; - uint8_t reserved: 4; - } house_adv_sentiment; + struct advanced_sentiment house_adv_sentiment; unsigned char show_on_problem_overlay; unsigned char house_tavern_wine_access; unsigned char house_tavern_food_access; diff --git a/src/building/state.h b/src/building/state.h index 684a56009b..a5bf163d51 100644 --- a/src/building/state.h +++ b/src/building/state.h @@ -11,7 +11,7 @@ #define BUILDING_STATE_TOURISM_BUFFER_SIZE (BUILDING_STATE_ORIGINAL_BUFFER_SIZE + 6) // 134 #define BUILDING_STATE_VARIANTS_AND_UPGRADES (BUILDING_STATE_TOURISM_BUFFER_SIZE + 2) // 136 #define BUILDING_STATE_STRIKES (BUILDING_STATE_VARIANTS_AND_UPGRADES + 1) // 137 -#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + 1) // 138 +#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + sizeof(advanced_sentiment)) // 138 #define BUILDING_STATE_SICKNESS (BUILDING_STATE_ADV_SENTIMENT + 5) // 143 #define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 127 (plus variable resource size) #define BUILDING_STATE_DYNAMIC_RESOURCES (BUILDING_STATE_WITHOUT_RESOURCES + BUILDING_STATE_NONSTATIC_RESOURCE_SIZE) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 97781b1a6d..ebcf7385be 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -338,7 +338,7 @@ const int advanced_sentiment_drop_modifier[5] = { }; // Checks if house building still has a cooldown before apply advanced sentiment change logic -int is_house_has_ongoing_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { +int check_house_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { if (!building_is_house(b->type) || !b->house_adv_sentiment.cooldown_initialized) { return 0; } @@ -445,7 +445,7 @@ void city_sentiment_update(int update_sentiment_cooldown) int sentiment_delta = sentiment - b->sentiment.house_happiness; if (sentiment_delta != 0 && apply_advanced_sentiment_change && - !is_house_has_ongoing_advanced_sentiment_change_cooldown(b, update_sentiment_cooldown)) { + !check_house_advanced_sentiment_change_cooldown(b, update_sentiment_cooldown)) { // With new advanced logic we introduce faster sentiment change when the target value is // far away from current happiness level. The final change value depends on difficulty settings. // Example #1: From c834aad86fcfae2adfdb603fa05faeb31279c8f2 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 21 Jan 2025 23:37:34 -0500 Subject: [PATCH 17/25] simplify a logic for gain/loss sentiment points, lower punishment --- src/city/sentiment.c | 120 +++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index ebcf7385be..b3c3ee4ec2 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -179,41 +179,43 @@ static int get_wage_sentiment_modifier(void) int use_advanced_sentiment_contribution = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION); int wage_differential = city_data.labor.wages - city_data.labor.wages_rome; if (use_advanced_sentiment_contribution && wage_differential > wage_interval) { - // Precomputed wage sentiment contributions by intervals. Each next interval gives twice less - // contribution in compare to previous, making it inefficient to set wages much higher than Rome. - // When wages differential is more than 32 dn, it stops contributing to sentiment. - const int contribution_div[4] = { 1, 2, 4, 8 }; // Divisors for the remainder - const int contribution[4] = { 8, 12, 14, 15 }; // Precomputed results for full wage intervals - const int max_interval_idx = sizeof(contribution) / sizeof(contribution[0]); - - // Determine the interval index and remainder contribution - int interval_idx = wage_differential / wage_interval; - if (interval_idx >= max_interval_idx) { - // Stop contributing if wage diff value is 32 or higher - wage_differential = contribution[max_interval_idx - 1] * WAGE_POSITIVE_MODIFIER; - } else { - // For better int precision, we multiply the reminder by wage modifier before division - int remainder = (wage_differential % wage_interval) * WAGE_POSITIVE_MODIFIER / contribution_div[interval_idx]; - wage_differential = contribution[interval_idx - 1] * WAGE_POSITIVE_MODIFIER + remainder; + // Extra sentiment bonus modifier applies when player sets higher wages than Rome. Wage range is + // divided by 8dn intervals. For every next wage interval the modifier is decreased by 1/2. + // Example: + // Rome pays 30dn, player sets current wage level to 55dn. Wage difference will be 25dn and + // the interval length is 8dn. Base bonus modifier is 2. Modifier will be set for every + // wage interval to values [2, 1, 0.5, 0.25]. + // The final modifier: 8 * 2 + 8 * 1 + 8 * 0.5 + 1 * 0.25) = 28 (original value was 50). + int remaining = abs(wage_differential); + wage_differential = 0; + + int modifier = 100 * WAGE_POSITIVE_MODIFIER; + while (remaining > 0) { + int diff = calc_bound(remaining, 1, wage_interval); + wage_differential += diff * modifier; + remaining -= diff; + modifier >>= 1; // reduces sentiment bonus modifier by 50% } + wage_differential /= 100; } else if (use_advanced_sentiment_contribution && wage_differential < -wage_interval) { - int abs_wage_differential = abs(wage_differential); - // Precomputed wage sentiment punishment by intervals. Each next interval gives doubled - // punishment in compare to previous, making it inefficient to set wages much lower than Rome. - // When wages differential is less than -48 dn, the punishment for every next denarii is at fixed rate - const int punishment[6] = { -8, -24, -56, -120, -248, -504 }; // Precomputed results for full wage intervals - const int max_interval_idx = sizeof(punishment) / sizeof(punishment[0]); - - // Determine the interval index and remainder punishment - int interval_idx = abs_wage_differential / wage_interval; - if (interval_idx >= max_interval_idx) { - // Use the fixed punishment modifier for values out of pre-computed intervals range. - int remainder = (abs_wage_differential - (max_interval_idx * wage_interval)) << max_interval_idx; - wage_differential = (punishment[max_interval_idx - 1] - remainder) * WAGE_NEGATIVE_MODIFIER; - } else { - int remainder = (abs_wage_differential % wage_interval) * (2 << (interval_idx - 1)); - wage_differential = (punishment[interval_idx - 1] - remainder) * WAGE_NEGATIVE_MODIFIER; + // Extra sentiment punishment modifier applies when player sets lower wages than Rome. Wage range is + // divided by 8dn intervals. For every next wage interval the modifier is increased by 1/2. + // Example: + // Rome pays 40dn, player sets current wage level to 15dn. Wage difference will be -25dn and + // the interval length is 8dn. Base punishment modifier is 3. Modifier will be set for every + // wage interval to values [3, 4.5, 6.75, 10.125]. + // The final modifier: -(8 * 3 + 8 * 4.5 + 8 * 6.75 + 1 * 10.125) = -124 (original value was -75). + int remaining = abs(wage_differential); + wage_differential = 0; + + int modifier = 100 * WAGE_NEGATIVE_MODIFIER; + while (remaining > 0) { + int diff = calc_bound(remaining, 1, wage_interval); + wage_differential -= diff * modifier; + remaining -= diff; + modifier += modifier / 2; // adds 50% sentiment points reduction } + wage_differential /= 100; } else { wage_differential *= (wage_differential > 0 ? WAGE_POSITIVE_MODIFIER : WAGE_NEGATIVE_MODIFIER); } @@ -237,26 +239,28 @@ static int get_sentiment_modifier_for_tax_rate(int tax) if (sentiment_modifier < -interval && config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION)) { // Extra sentiment punishment modifier applies when player sets higher taxes. Tax range is // divided by intervals which length is half of base tax rate based on difficulty settings. - // For every next tax interval the modifier is doubled. + // For every next tax interval the modifier is increased by 1/3. // Example: // In very hard mode the base tax rate is 6%. Player sets current tax level to 16%. // Tax difference will be 10% and the interval length is 3% (half of base tax rate 6%). - // Punishment modifier will be set for every tax interval to values [1, 2, 4, 8]. - // The final modifier: -(3% * 1 + 3% * 2 + 3% * 4 + 1% * 8) * (12% - 6%) = -174 (original value was -60). + // Base punishment modifier is a diff between 12% and base tax rate (6%). + // Modifier will be set for every tax interval to values [6, 8, 10.66, 14.2]. + // The final modifier: -(3% * 6 + 3% * 8 + 3% * 10.66 + 1% * 14.2) = -88 (original value was -60). int remaining = abs(sentiment_modifier); sentiment_modifier = 0; - int modifier = 1; + int modifier = 100 * (MAX_TAX_MULTIPLIER - base_tax); while (remaining > 0) { int diff = calc_bound(remaining, 1, interval); sentiment_modifier -= diff * modifier; remaining -= diff; - if (modifier < 512) { - modifier <<= 1; // Multiply by 2 - } + modifier += modifier / 3; // adds 33% sentiment points reduction } + sentiment_modifier /= 100; + } else { + sentiment_modifier *= sentiment_modifier < 0 ? (MAX_TAX_MULTIPLIER - base_tax) : (base_tax / 2); } - sentiment_modifier *= sentiment_modifier < 0 ? (MAX_TAX_MULTIPLIER - base_tax) : (base_tax / 2); + return sentiment_modifier; } @@ -322,19 +326,19 @@ static int extra_food_bonus(int types, int required) } const int advanced_sentiment_gain_modifier[5] = { - 400, // 25% - 463, // 21.6% - 546, // 18.3% - 666, // 15% - 800 // 12.5% + 30, // Very Easy + 25, // Easy + 20, // Normal + 17, // Hard + 15 // Very Hard }; const int advanced_sentiment_drop_modifier[5] = { - 400, // 25% - 333, // 30% - 285, // 35% - 250, // 40% - 200 // 50% + 30, // Very Easy + 35, // Easy + 40, // Normal + 45, // Hard + 50 // Very Hard }; // Checks if house building still has a cooldown before apply advanced sentiment change logic @@ -406,11 +410,11 @@ void city_sentiment_update(int update_sentiment_cooldown) } int sentiment = default_sentiment; - - if (b->house_tax_coverage) { - sentiment += sentiment_contribution_taxes; + if (b->subtype.house_level > HOUSE_GRAND_INSULA) { + // Reduce sentiment contribution from taxes for villas by 20% + sentiment += (b->house_tax_coverage ? sentiment_contribution_taxes : sentiment_contribution_no_tax) * 8 / 10; } else { - sentiment += sentiment_contribution_no_tax; + sentiment += b->house_tax_coverage ? sentiment_contribution_taxes : sentiment_contribution_no_tax; } if (b->subtype.house_level <= HOUSE_GRAND_INSULA) { @@ -458,15 +462,11 @@ void city_sentiment_update(int update_sentiment_cooldown) // The delta percent relative to the current happiness level is 74% (57 * 100% / 77). // The final happiness change for Hard mode will be 6 (11% of 57, which is 15% of delta percent). if (sentiment_delta > 0) { - int happiness_target = calc_bound(b->sentiment.house_happiness + sentiment_delta, 1, 100); - int delta_percent = sentiment_delta * 100 / happiness_target; int gain_modifier = advanced_sentiment_gain_modifier[setting_difficulty()]; - sentiment_delta = calc_bound(sentiment_delta * delta_percent / gain_modifier, 1, 100); + sentiment_delta = calc_bound(sentiment_delta * gain_modifier / 100, 1, 100); } else { - int delta_percent = b->sentiment.house_happiness == 0 ? - 100 : (-sentiment_delta * 100 / b->sentiment.house_happiness); int drop_modifier = advanced_sentiment_drop_modifier[setting_difficulty()]; - sentiment_delta = calc_bound(sentiment_delta * delta_percent / drop_modifier, -100, -1); + sentiment_delta = calc_bound(sentiment_delta * drop_modifier / 100, -100, -1); } } else { sentiment_delta = calc_bound(sentiment_delta, -MAX_SENTIMENT_CHANGE, MAX_SENTIMENT_CHANGE); From 17db04dd067ed7ede5abaa4c2a7c845d70f84a69 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Tue, 21 Jan 2025 23:45:00 -0500 Subject: [PATCH 18/25] update examples for gain/loss house happiness --- src/city/sentiment.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index b3c3ee4ec2..eb42ab3c6b 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -454,13 +454,10 @@ void city_sentiment_update(int update_sentiment_cooldown) // far away from current happiness level. The final change value depends on difficulty settings. // Example #1: // Current house happiness level is 82, the new sentiment value is 10 and the delta is -72. - // The delta percent relative to the current happiness level is 87% (72 * 100% / 82). - // The final happiness change for VeryHard mode will be -30 (43% of -72, which is - // 50% of delta percent). + // The final happiness change for VeryHard mode will be -28 (40% of -72). // Example #2: // Current house happiness level is 20, the new sentiment value is 77 and the delta is 57. - // The delta percent relative to the current happiness level is 74% (57 * 100% / 77). - // The final happiness change for Hard mode will be 6 (11% of 57, which is 15% of delta percent). + // The final happiness change for Hard mode will be 9 (17% of 57). if (sentiment_delta > 0) { int gain_modifier = advanced_sentiment_gain_modifier[setting_difficulty()]; sentiment_delta = calc_bound(sentiment_delta * gain_modifier / 100, 1, 100); From db4c714c55d54a009865d0cb58b90303bd03c95c Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:38:33 -0500 Subject: [PATCH 19/25] apply suggestions --- src/building/building.c | 17 +--------------- src/building/building.h | 22 +++------------------ src/building/state.c | 13 ++++-------- src/building/state.h | 6 +++--- src/city/sentiment.c | 44 +++++++++++++++++++++++------------------ src/city/sentiment.h | 2 +- src/game/tick.c | 5 ++--- 7 files changed, 39 insertions(+), 70 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index 630bb0d67f..4cd10dfa33 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -172,21 +172,6 @@ static void remove_adjacent_types(building *b) b->next_of_type = 0; } -void initialize_sentiment_cooldown(building *b) { - if (b->house_adv_sentiment.cooldown_initialized) { - return; - } - - b->house_adv_sentiment.cooldown_initialized = 1; - - if (b->type <= BUILDING_HOUSE_GRAND_INSULA) { - b->house_adv_sentiment.cooldown = ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS; - } else { - // Do not apply cooldown to villas - b->house_adv_sentiment.cooldown = 0; - } -} - building *building_create(building_type type, int x, int y) { building *b; @@ -220,7 +205,7 @@ building *building_create(building_type type, int x, int y) // subtype if (building_is_house(type)) { - initialize_sentiment_cooldown(b); + b->cooldown_advanced_sentiment = type < BUILDING_HOUSE_SMALL_VILLA ? ADVANCED_SENTIMENT_COOLDOWN_TICKS : 0; b->subtype.house_level = type - BUILDING_HOUSE_VACANT_LOT; } diff --git a/src/building/building.h b/src/building/building.h index 6f742575ac..f8345d4cf3 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -8,12 +8,8 @@ #include "translation/translation.h" // Ticks of cooldown before new advanced sentiment logic will be applied -// for the house building. Each tick is equal to 3 months. That value -// shouldn't ever exceed 7, since it takes 3 bits of data. -// To extend or reduce the cooldown duration edit the -// ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS preprocessor definition. -#define ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS 7 -#define ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS 3 +// for the house building. Each tick is equal to 8 days (half of month). +#define ADVANCED_SENTIMENT_COOLDOWN_TICKS 36 typedef enum order_condition_type { ORDER_CONDITION_NEVER = 0, @@ -22,12 +18,6 @@ typedef enum order_condition_type { ORDER_CONDITION_DESTINATION_HAS_LESS_THAN } order_condition_type; -typedef struct advanced_sentiment { - uint8_t cooldown_initialized: 1; - uint8_t cooldown: 3; - uint8_t reserved: 4; -} advanced_sentiment; - typedef struct order { resource_type resource_type; int src_storage_id; @@ -194,11 +184,7 @@ typedef struct building { signed char house_happiness; signed char native_anger; } sentiment; - // New advanced sentiment contribution logic requires cooldown for newly built houses. - // The new happiness gain/drop logic will not be applied until cooldown expires. - // Cooldown ticks get decreased every Jan/Apr/Jul/Oct, which gives 18-20 months in total. - // That should be enough to build new housing block and evolve it. - struct advanced_sentiment house_adv_sentiment; + uint8_t cooldown_advanced_sentiment; unsigned char show_on_problem_overlay; unsigned char house_tavern_wine_access; unsigned char house_tavern_food_access; @@ -239,8 +225,6 @@ building *building_main(building *b); building *building_next(building *b); -void initialize_sentiment_cooldown(building *b); - building *building_create(building_type type, int x, int y); void building_clear_related_data(building *b); diff --git a/src/building/state.c b/src/building/state.c index 0663c13d70..0e1dad05af 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -167,11 +167,10 @@ void building_state_save_to_buffer(buffer *buf, const building *b) buffer_write_u8(buf, b->storage_id); buffer_write_i8(buf, b->sentiment.house_happiness); // which union field we use does not matter - assert (sizeof(b->house_adv_sentiment) == sizeof(uint8_t)); if (building_is_house(b->type)) { - buffer_write_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment)); + buffer_write_u8(buf, b->cooldown_advanced_sentiment); } else { - buffer_skip(buf, sizeof(b->house_adv_sentiment)); + buffer_skip(buf, sizeof(b->cooldown_advanced_sentiment)); } buffer_write_u8(buf, b->show_on_problem_overlay); @@ -505,9 +504,9 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter if (save_version >= SAVE_GAME_LAST_ADVANCED_SENTIMENT) { if (building_is_house(b->type)) { - buffer_read_raw(buf, &b->house_adv_sentiment, sizeof(b->house_adv_sentiment)); + b->cooldown_advanced_sentiment = buffer_read_u8(buf); } else { - buffer_skip(buf, sizeof(b->house_adv_sentiment)); + buffer_skip(buf, sizeof(b->cooldown_advanced_sentiment)); } } b->show_on_problem_overlay = buffer_read_u8(buf); @@ -709,8 +708,4 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ if (building_buf_size > BUILDING_STATE_CURRENT_BUFFER_SIZE) { buffer_skip(buf, building_buf_size - BUILDING_STATE_CURRENT_BUFFER_SIZE); } - - if (building_is_house(b->type)) { - initialize_sentiment_cooldown(b); - } } diff --git a/src/building/state.h b/src/building/state.h index a5bf163d51..f8b7ac5934 100644 --- a/src/building/state.h +++ b/src/building/state.h @@ -11,11 +11,11 @@ #define BUILDING_STATE_TOURISM_BUFFER_SIZE (BUILDING_STATE_ORIGINAL_BUFFER_SIZE + 6) // 134 #define BUILDING_STATE_VARIANTS_AND_UPGRADES (BUILDING_STATE_TOURISM_BUFFER_SIZE + 2) // 136 #define BUILDING_STATE_STRIKES (BUILDING_STATE_VARIANTS_AND_UPGRADES + 1) // 137 -#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + sizeof(advanced_sentiment)) // 138 -#define BUILDING_STATE_SICKNESS (BUILDING_STATE_ADV_SENTIMENT + 5) // 143 -#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 127 (plus variable resource size) +#define BUILDING_STATE_SICKNESS (BUILDING_STATE_ADV_SENTIMENT + 5) // 142 +#define BUILDING_STATE_WITHOUT_RESOURCES (BUILDING_STATE_SICKNESS - RESOURCE_MAX_LEGACY) // 126 (plus variable resource size) #define BUILDING_STATE_DYNAMIC_RESOURCES (BUILDING_STATE_WITHOUT_RESOURCES + BUILDING_STATE_NONSTATIC_RESOURCE_SIZE) #define BUILDING_STATE_CURRENT_BUFFER_SIZE (BUILDING_STATE_DYNAMIC_RESOURCES + 8) +#define BUILDING_STATE_ADV_SENTIMENT (BUILDING_STATE_STRIKES + sizeof(uint8_t)) void building_state_save_to_buffer(buffer *buf, const building *b); diff --git a/src/city/sentiment.c b/src/city/sentiment.c index eb42ab3c6b..fac4ec657e 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -37,6 +37,13 @@ #define IMPERIAL_GAMES_SENTIMENT_BONUS 15 #define POP_STEP_FOR_BASE_AVERAGE_HOUSE_LEVEL 625 +#define min(a,b) \ +({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + // New advanced sentiment change calculation applies only after configured months // of gameplay has passed. This is required to prevent very fast sentiment drop // by high unemployment at very early game @@ -341,36 +348,34 @@ const int advanced_sentiment_drop_modifier[5] = { 50 // Very Hard }; -// Checks if house building still has a cooldown before apply advanced sentiment change logic -int check_house_advanced_sentiment_change_cooldown(building *b, int update_sentiment_cooldown) { - if (!building_is_house(b->type) || !b->house_adv_sentiment.cooldown_initialized) { +// Updates house building sentiment cooldown by delta value. +// Returns 1 if advanced sentiment logic should be applied to house and 0 if not +int update_house_advanced_sentiment_cooldown(building *b, int sentiment_cooldown_delta) { + if (!building_is_house(b->type)) { return 0; } - if (b->type > BUILDING_HOUSE_GRAND_INSULA) { + if (b->type >= BUILDING_HOUSE_SMALL_VILLA) { // Reset cooldown for villas - b->house_adv_sentiment.cooldown = 0; - } else if (b->type == BUILDING_HOUSE_VACANT_LOT && b->house_adv_sentiment.cooldown == ADVANCED_SENTIMENT_COOLDOWN_MAX_TICKS) { + b->cooldown_advanced_sentiment = 0; + } else if (b->type == BUILDING_HOUSE_VACANT_LOT) { // Wait for new citizens to arrive - return 1; + return 0; } - if (update_sentiment_cooldown && - b->house_adv_sentiment.cooldown && - game_time_month() % ADVANCED_SENTIMENT_COOLDOWN_TICK_MONTHS == 0) { - // Decrease tick once configured amount of game months has passed. - b->house_adv_sentiment.cooldown--; + if (sentiment_cooldown_delta > 0 && b->cooldown_advanced_sentiment > 0) { + b->cooldown_advanced_sentiment -= min(sentiment_cooldown_delta, b->cooldown_advanced_sentiment); } - if (!b->house_adv_sentiment.cooldown) { + if (!b->cooldown_advanced_sentiment) { // Cooldown has ended - return 0; + return 1; } - return 1; + return 0; } -void city_sentiment_update(int update_sentiment_cooldown) +void city_sentiment_update(int sentiment_cooldown_delta) { city_population_check_consistency(); @@ -448,13 +453,14 @@ void city_sentiment_update(int update_sentiment_cooldown) // Change sentiment gradually to the new value int sentiment_delta = sentiment - b->sentiment.house_happiness; if (sentiment_delta != 0 && - apply_advanced_sentiment_change && - !check_house_advanced_sentiment_change_cooldown(b, update_sentiment_cooldown)) { + update_house_advanced_sentiment_cooldown(b, sentiment_cooldown_delta) && + apply_advanced_sentiment_change + ) { // With new advanced logic we introduce faster sentiment change when the target value is // far away from current happiness level. The final change value depends on difficulty settings. // Example #1: // Current house happiness level is 82, the new sentiment value is 10 and the delta is -72. - // The final happiness change for VeryHard mode will be -28 (40% of -72). + // The final happiness change for VeryHard mode will be -36 (50% of -72). // Example #2: // Current house happiness level is 20, the new sentiment value is 77 and the delta is 57. // The final happiness change for Hard mode will be 9 (17% of 57). diff --git a/src/city/sentiment.h b/src/city/sentiment.h index 02db1c9ba6..a159280f58 100644 --- a/src/city/sentiment.h +++ b/src/city/sentiment.h @@ -25,6 +25,6 @@ void city_sentiment_reduce_crime_cooldown(void); int city_sentiment_get_blessing_festival_boost(void); void city_sentiment_decrement_blessing_boost(void); -void city_sentiment_update(int update_sentiment_cooldown); +void city_sentiment_update(int sentiment_cooldown_delta); #endif // CITY_SENTIMENT_H diff --git a/src/game/tick.c b/src/game/tick.c index 60eda1186d..48e5ea3b1d 100644 --- a/src/game/tick.c +++ b/src/game/tick.c @@ -130,9 +130,8 @@ static void advance_day(void) if (game_time_advance_day()) { advance_month(); } - int update_sentiment_cooldown = game_time_day() == 0; - if (update_sentiment_cooldown || game_time_day() == 8) { - city_sentiment_update(update_sentiment_cooldown); + if (game_time_day() == 0 || game_time_day() == 8) { + city_sentiment_update(1); } if (game_time_day() == 0 || game_time_day() == 7) { building_lighthouse_consume_timber(); From cc909fecac6722ed1d25267d3ac5154a4f556cfe Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:40:59 -0500 Subject: [PATCH 20/25] rename building_is_storage_kind to building_uses_storage --- src/building/building.c | 4 ++-- src/building/building.h | 2 +- src/building/state.c | 2 +- src/figuretype/trader.c | 2 +- src/widget/city_overlay_other.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/building/building.c b/src/building/building.c index 4cd10dfa33..406e31f6fd 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -269,7 +269,7 @@ static void building_delete(building *b) void building_clear_related_data(building *b) { - if (building_is_storage_kind(b->type) && b->storage_id) { + if (building_uses_storage(b->type) && b->storage_id) { building_storage_delete(b->storage_id); b->storage_id = 0; } @@ -425,7 +425,7 @@ int building_is_house(building_type type) return type >= BUILDING_HOUSE_VACANT_LOT && type <= BUILDING_HOUSE_LUXURY_PALACE; } -int building_is_storage_kind(building_type type) +int building_uses_storage(building_type type) { return type == BUILDING_WAREHOUSE || type == BUILDING_GRANARY; } diff --git a/src/building/building.h b/src/building/building.h index f8345d4cf3..83dbf379a7 100644 --- a/src/building/building.h +++ b/src/building/building.h @@ -240,7 +240,7 @@ void building_update_desirability(void); /** * Checks if building can store goods */ -int building_is_storage_kind(building_type type); +int building_uses_storage(building_type type); int building_is_house(building_type type); diff --git a/src/building/state.c b/src/building/state.c index 0e1dad05af..692de7e901 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -495,7 +495,7 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->desirability = buffer_read_i8(buf); b->is_deleted = buffer_read_u8(buf); b->is_adjacent_to_water = buffer_read_u8(buf); - if (building_is_storage_kind(b->type)) { + if (building_uses_storage(b->type)) { b->storage_id = buffer_read_u8(buf); } else { b->storage_id = 0; diff --git a/src/figuretype/trader.c b/src/figuretype/trader.c index 7b95ac0781..566b1743d4 100644 --- a/src/figuretype/trader.c +++ b/src/figuretype/trader.c @@ -128,7 +128,7 @@ int figure_trade_caravan_can_buy(figure *trader, int building_id, int city_id) int figure_trade_caravan_can_sell(figure *trader, int building_id, int city_id) { building *b = building_get(building_id); - if (!building_is_storage_kind(b->type)) { + if (!building_uses_storage(b->type)) { return 0; } if (b->has_plague) { diff --git a/src/widget/city_overlay_other.c b/src/widget/city_overlay_other.c index 7ce348d2ef..c1ab9c206f 100644 --- a/src/widget/city_overlay_other.c +++ b/src/widget/city_overlay_other.c @@ -116,7 +116,7 @@ static int show_building_logistics(const building *b) static int show_building_storages(const building *b) { b = building_main((building *) b); - return building_is_storage_kind(b->type) && b->storage_id > 0 && building_storage_get(b->storage_id); + return building_uses_storage(b->type) && b->storage_id > 0 && building_storage_get(b->storage_id); } static int show_building_none(const building *b) @@ -915,7 +915,7 @@ static void draw_storage_ids(int x, int y, float scale, int grid_offset) } int building_id = map_building_at(grid_offset); building *b = building_get(building_id); - if (!b || !building_is_storage_kind(b->type) || b->is_deleted || map_property_is_deleted(b->grid_offset) || + if (!b || !building_uses_storage(b->type) || b->is_deleted || map_property_is_deleted(b->grid_offset) || !b->storage_id || !map_property_is_draw_tile(grid_offset)) { return; } From 8993c5c93e9758f95e835a410bf0d6cbb42157de Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:42:58 -0500 Subject: [PATCH 21/25] remove redundant comment --- src/building/state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/building/state.c b/src/building/state.c index 692de7e901..00ffd45d2b 100644 --- a/src/building/state.c +++ b/src/building/state.c @@ -499,7 +499,7 @@ void building_state_load_from_buffer(buffer *buf, building *b, int building_buf_ b->storage_id = buffer_read_u8(buf); } else { b->storage_id = 0; - buffer_skip(buf, 1); // do not load storage_id for non-storage buildings + buffer_skip(buf, 1); } b->sentiment.house_happiness = buffer_read_i8(buf); // which union field we use does not matter if (save_version >= SAVE_GAME_LAST_ADVANCED_SENTIMENT) { From d7bbfb7dbdc8b3cdd45062d6bc1bb4cb7c601daf Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:49:05 -0500 Subject: [PATCH 22/25] apply suggestion for population check instead of months --- src/city/sentiment.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index fac4ec657e..742d66df10 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -44,10 +44,10 @@ _a < _b ? _a : _b; \ }) -// New advanced sentiment change calculation applies only after configured months -// of gameplay has passed. This is required to prevent very fast sentiment drop +// New advanced sentiment change calculation applies only after city reaches +// population of 1000. This is required to prevent very fast sentiment drop // by high unemployment at very early game -#define ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS 30 +#define ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_POPULATION 1000 int city_sentiment(void) { @@ -395,7 +395,7 @@ void city_sentiment_update(int sentiment_cooldown_delta) int total_houses = 0; int house_level_sentiment_multiplier = 3; int apply_advanced_sentiment_change = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION) && - game_time_total_months() >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_MONTHS; + city_data.population.population >= ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_POPULATION; for (building_type type = BUILDING_HOUSE_SMALL_TENT; type <= BUILDING_HOUSE_LUXURY_PALACE; type++) { if (type == BUILDING_HOUSE_SMALL_SHACK) { From 5876bde05f1e33b00e5fd7113ee1a4bea11ae071 Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:56:43 -0500 Subject: [PATCH 23/25] make wage interval a preprocessor definition --- src/city/sentiment.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index 742d66df10..d129dd8069 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -49,6 +49,10 @@ // by high unemployment at very early game #define ADVANCED_SENTIMENT_CHANGE_APPLY_AFTER_POPULATION 1000 +// The effect from wages setting is divided by 8dn intervals. Each next interval +// reduces or increases modifier for every denarii set above or below Rome pays. +#define WAGE_SENTIMENT_CHANGE_INTERVAL 8 + int city_sentiment(void) { return city_data.sentiment.value; @@ -182,7 +186,7 @@ static int get_games_bonus(void) static int get_wage_sentiment_modifier(void) { - const int wage_interval = 8; + const int wage_interval = WAGE_SENTIMENT_CHANGE_INTERVAL; int use_advanced_sentiment_contribution = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION); int wage_differential = city_data.labor.wages - city_data.labor.wages_rome; if (use_advanced_sentiment_contribution && wage_differential > wage_interval) { From 4e8dff688f07b539808856871da7b8a8f1e9837c Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 16:58:27 -0500 Subject: [PATCH 24/25] add early return for case when wages set to exactly the same amount Rome pays --- src/city/sentiment.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index d129dd8069..c43cabefdc 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -186,6 +186,9 @@ static int get_games_bonus(void) static int get_wage_sentiment_modifier(void) { + if (city_data.labor.wages == city_data.labor.wages_rome) { + return 0; + } const int wage_interval = WAGE_SENTIMENT_CHANGE_INTERVAL; int use_advanced_sentiment_contribution = config_get(CONFIG_GP_CH_ADVANCED_TAX_WAGE_SENTIMENT_CONTRIBUTION); int wage_differential = city_data.labor.wages - city_data.labor.wages_rome; From a5e5c5d4895c06d657cf49af725419c4c23a5a8d Mon Sep 17 00:00:00 2001 From: ZelionD Date: Mon, 3 Feb 2025 17:11:41 -0500 Subject: [PATCH 25/25] replace shr by div --- src/city/sentiment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/city/sentiment.c b/src/city/sentiment.c index c43cabefdc..446546ae10 100644 --- a/src/city/sentiment.c +++ b/src/city/sentiment.c @@ -208,7 +208,7 @@ static int get_wage_sentiment_modifier(void) int diff = calc_bound(remaining, 1, wage_interval); wage_differential += diff * modifier; remaining -= diff; - modifier >>= 1; // reduces sentiment bonus modifier by 50% + modifier /= 2; } wage_differential /= 100; } else if (use_advanced_sentiment_contribution && wage_differential < -wage_interval) {