diff --git a/C3X.h b/C3X.h index 592f9f80..3e6b43bc 100644 --- a/C3X.h +++ b/C3X.h @@ -227,6 +227,12 @@ enum ai_auto_build_great_wall_strategy { AAGWS_OTHER_CIV_BORDERED_ONLY }; +enum pollution_spawn_effect { + PSE_DEFAULT = 0, + PSE_REDUCE_POPULATION, + PSE_REDUCE_POPULATION_AND_POLLUTE_TILE +}; + enum perfume_kind { PK_PRODUCTION = 0, PK_TECHNOLOGY, @@ -327,6 +333,7 @@ struct c3x_config { bool dont_end_units_turn_after_airdrop; bool allow_airdrop_without_airport; bool enable_negative_pop_pollution; + enum pollution_spawn_effect pollution_spawn_effect; bool enable_pollution_from_free_improvements; enum retreat_rules land_retreat_rules; enum retreat_rules sea_retreat_rules; @@ -669,6 +676,7 @@ enum c3x_label { CL_OBSOLETED_BY, CL_NO_STEALTH_ATTACK, CL_DODGED_SAM, + CL_POLLUTION_REDUCES_POP, CL_PREVIEW, CL_CITY_TOO_CLOSE_BUTTON_TOOLTIP, CL_TOTAL_CITIES, diff --git a/Text/c3x-labels.txt b/Text/c3x-labels.txt index 80d84e88..86b41c7e 100644 --- a/Text/c3x-labels.txt +++ b/Text/c3x-labels.txt @@ -52,6 +52,9 @@ Obsoleted By ; Pops up on the map when a bomber gets intercepted by enemy AA buildings but dodges the damage We were chased off by enemy air defenses. +; Pops up on the map when pollution reduces a city's population instead of spawning on a tile. +Pollution reduces population of + ; As in a "preview" version of the mod. Used on the mod info popup. Preview diff --git a/civ_prog_objects.csv b/civ_prog_objects.csv index d426e178..054b073a 100644 --- a/civ_prog_objects.csv +++ b/civ_prog_objects.csv @@ -214,6 +214,7 @@ inlead, 0x4BED80, 0x4C6350, 0x4BEE10, "City_cycle_specialist_type", "bool ( inlead, 0x4B1C10, 0x4B8BC0, 0x4B1CA0, "City_get_total_pollution", "int (__fastcall *) (City * this)" inlead, 0x4B1B40, 0x4B8B00, 0x4B1BD0, "City_get_pollution_from_buildings", "int (__fastcall *) (City * this)" inlead, 0x4B1A50, 0x4B8A10, 0x4B1AE0, "City_get_pollution_from_pop", "int (__fastcall *) (City * this)" +inlead, 0x4B2F80, 0x0, 0x0, "City_update_spawn_pollution", "void (__fastcall *) (City * this)" inlead, 0x4ACF40, 0x4B3F20, 0x4ACFD0, "City_add_or_remove_improvement", "void (__fastcall *) (City * this, int edx, int improv_id, int add, bool param_3)" define, 0x57E943, 0x58B68E, 0x57E6A3, "ADDR_RESOURCE_TILE_COUNT_MASK", "void *" define, 0x57E5EB, 0x58B328, 0x57E34B, "ADDR_RESOURCE_TILE_COUNT_ZERO_COMPARE", "void *" diff --git a/default.c3x_config.ini b/default.c3x_config.ini index 118a8379..81fd15ba 100644 --- a/default.c3x_config.ini +++ b/default.c3x_config.ini @@ -486,6 +486,11 @@ dont_end_units_turn_after_airdrop = false allow_airdrop_without_airport = false enable_negative_pop_pollution = true +; Controls what happens when pollution may spawn from a city. +; Options are "default", "reduce-population", and "reduce-population-and-pollute-tile". +; In "reduce-population-and-pollute-tile" mode, the population reduction and tile pollution checks run independently. +pollution_spawn_effect = default + ; Causes improvements granted for free by great or small wonders to contribute pollution as though they had been built in the city. enable_pollution_from_free_improvements = false diff --git a/injected_code.c b/injected_code.c index 7c1b736d..889a76b7 100644 --- a/injected_code.c +++ b/injected_code.c @@ -2182,6 +2182,17 @@ read_ai_auto_build_great_wall_strategy (struct string_slice const * s, int * out return false; } +bool +read_pollution_spawn_effect (struct string_slice const * s, int * out_val) +{ + struct string_slice trimmed = trim_string_slice (s, 1); + if (slice_matches_str (&trimmed, "default" )) { *out_val = PSE_DEFAULT; return true; } + else if (slice_matches_str (&trimmed, "reduce-population" )) { *out_val = PSE_REDUCE_POPULATION; return true; } + else if (slice_matches_str (&trimmed, "reduce-population-and-pollute-tile" )) { *out_val = PSE_REDUCE_POPULATION_AND_POLLUTE_TILE; return true; } + else + return false; +} + bool read_tile_terrain_type_value (struct string_slice const * s, enum SquareTypes * out_type) { @@ -2754,6 +2765,9 @@ load_config (char const * file_path, int path_is_relative_to_mod_dir) } else if (slice_matches_str (&p.key, "sea_retreat_rules")) { if (! read_retreat_rules (&value, (int *)&cfg->sea_retreat_rules)) handle_config_error (&p, CPE_BAD_VALUE); + } else if (slice_matches_str (&p.key, "pollution_spawn_effect")) { + if (! read_pollution_spawn_effect (&value, (int *)&cfg->pollution_spawn_effect)) + handle_config_error (&p, CPE_BAD_VALUE); } else if (slice_matches_str (&p.key, "draw_lines_using_gdi_plus")) { if (! read_line_drawing_override (&value, (int *)&cfg->draw_lines_using_gdi_plus)) handle_config_error (&p, CPE_BAD_VALUE); @@ -19532,6 +19546,7 @@ patch_init_floating_point () base_config.distribution_hub_yield_division_mode = DHYDM_FLAT; base_config.ai_distribution_hub_build_strategy = ADHBS_BY_CITY_COUNT; base_config.ai_auto_build_great_wall_strategy = AAGWS_ALL_BORDERS; + base_config.pollution_spawn_effect = PSE_DEFAULT; base_config.great_wall_auto_build_wonder_improv_id = -1; for (int n = 0; n < ARRAY_LEN (boolean_config_options); n++) *((char *)&base_config + boolean_config_options[n].offset) = boolean_config_options[n].base_val; @@ -26287,6 +26302,29 @@ patch_City_get_total_pollution (City * this) return patch_City_get_pollution_from_buildings (this) + patch_City_get_pollution_from_pop (this); } +void __fastcall +patch_City_update_spawn_pollution (City * this) +{ + enum pollution_spawn_effect effect = is->current_config.pollution_spawn_effect; + if (effect == PSE_DEFAULT) { + City_update_spawn_pollution (this); + return; + } else if (effect == PSE_REDUCE_POPULATION_AND_POLLUTE_TILE) + City_update_spawn_pollution (this); + + int pollution = patch_City_get_total_pollution (this); + if ((pollution > 0) && (rand_int (p_rand_object, __, 100) < pollution) && (this->Body.Population.Size > 1)) { + City_remove_population (this, __, 1, -1, '\0'); + + if (this->Body.CivID == p_main_screen_form->Player_CivID) { + char msg[160]; + snprintf (msg, sizeof msg, "%s %s", is->c3x_labels[CL_POLLUTION_REDUCES_POP], this->Body.CityName); + msg[(sizeof msg) - 1] = '\0'; + show_map_specific_text (this->Body.X, this->Body.Y, msg, true); + } + } +} + void remove_extra_palaces (City * city, City * excluded_destination); void