From 58b165d1195dd96aac1747cf755fe89f3827a28e Mon Sep 17 00:00:00 2001 From: ineveraskedforthis Date: Sat, 7 Jun 2025 00:31:23 +0300 Subject: [PATCH 1/2] adjust urban sprawl to work better with different map sizes --- src/economy/economy.cpp | 2 +- src/gamestate/serialization.cpp | 3 ++ src/map/map.cpp | 49 ++++++++++++++++++++++----------- src/map/map.hpp | 1 + src/map/map_data_loading.cpp | 22 +++++++++++++++ src/parsing/defines.hpp | 2 ++ 6 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/economy/economy.cpp b/src/economy/economy.cpp index 6d1d3edb9..7de75f7a8 100644 --- a/src/economy/economy.cpp +++ b/src/economy/economy.cpp @@ -745,7 +745,7 @@ void initialize(sys::state& state) { province::for_each_land_province(state, [&](dcon::province_id p) { auto fp = fatten(state.world, p); //max size of exploitable land: - auto max_rgo_size = std::ceil(4000.f * state.map_state.map_data.province_area[province::to_map_id(p)]); + auto max_rgo_size = std::ceil(state.map_state.map_data.province_area_km2[province::to_map_id(p)]); // currently exploited land float pop_amount = 0.0f; for(auto pt : state.world.in_pop_type) { diff --git a/src/gamestate/serialization.cpp b/src/gamestate/serialization.cpp index 663d9f508..66ecdcaed 100644 --- a/src/gamestate/serialization.cpp +++ b/src/gamestate/serialization.cpp @@ -150,6 +150,7 @@ uint8_t const* read_scenario_section(uint8_t const* ptr_in, uint8_t const* secti ptr_in = deserialize(ptr_in, state.map_state.map_data.terrain_id_map); ptr_in = deserialize(ptr_in, state.map_state.map_data.province_id_map); ptr_in = deserialize(ptr_in, state.map_state.map_data.province_area); + ptr_in = deserialize(ptr_in, state.map_state.map_data.province_area_km2); ptr_in = deserialize(ptr_in, state.map_state.map_data.diagonal_borders); } { @@ -331,6 +332,7 @@ uint8_t* write_scenario_section(uint8_t* ptr_in, sys::state& state) { ptr_in = serialize(ptr_in, state.map_state.map_data.terrain_id_map); ptr_in = serialize(ptr_in, state.map_state.map_data.province_id_map); ptr_in = serialize(ptr_in, state.map_state.map_data.province_area); + ptr_in = serialize(ptr_in, state.map_state.map_data.province_area_km2); ptr_in = serialize(ptr_in, state.map_state.map_data.diagonal_borders); } { @@ -512,6 +514,7 @@ scenario_size sizeof_scenario_section(sys::state& state) { sz += serialize_size(state.map_state.map_data.terrain_id_map); sz += serialize_size(state.map_state.map_data.province_id_map); sz += serialize_size(state.map_state.map_data.province_area); + sz += serialize_size(state.map_state.map_data.province_area_km2); sz += serialize_size(state.map_state.map_data.diagonal_borders); } { sz += sizeof(parsing::defines); } diff --git a/src/map/map.cpp b/src/map/map.cpp index daebddccb..0f15cfcdf 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -2342,13 +2342,16 @@ bool get_provinces_part_of_rr_path(sys::state& state, std::vector& visited return true; } -glm::vec2 get_node(sys::state& state, glm::vec2 center, int i, int j) { +glm::vec2 get_node(sys::state& state, glm::vec2 center, int i, int j, int size_x, int size_y) { const auto rpx = rng::get_random(state, j ^ i ^ (uint32_t)center.x, i); const float rx = (float(rng::reduce(uint32_t(rpx), 8192)) / (8192.f)) - 0.5f; const auto rpy = rng::get_random(state, j ^ i ^ (uint32_t)center.y ^ 5653, j); const float ry = (float(rng::reduce(uint32_t(rpy), 8192)) / (8192.f)) - 0.5f; - auto base_shift = glm::vec2{ (float)i + rx, (float)j + ry } * 0.4f / sqrt(sqrt((float) (i * i) + (float) (j * j) + 1)); + auto scale_x = (float)size_x / 5600.f; + auto scale_y = (float)size_y / 2160.f; + + auto base_shift = glm::vec2{ ((float)i + rx) * scale_x, ((float)j + ry) * scale_y} * 0.4f / sqrt(sqrt((float) (i * i) + (float) (j * j) + 1)); return center + base_shift; } @@ -2362,25 +2365,29 @@ void display_data::update_sprawl(sys::state& state) { std::vector> connectors{}; connectors.resize(state.world.province_size()); + auto minimal_population_per_visible_settlement = 2500.f; + // Populate paths with railroads - only account provinces that have been visited // but not the adjacencies for(const auto p : state.world.in_province) { auto rural_population = 0.f; - for(auto wt : state.culture_definitions.rgo_workers) { - rural_population += state.world.province_get_demographics(p, demographics::to_key(state, wt)); + for(auto pt : state.world.in_pop_type) { + if(pt.get_is_paid_rgo_worker()) + rural_population += state.world.province_get_demographics(p, demographics::to_key(state, pt)); } - rural_population += state.world.province_get_demographics(p, demographics::to_employment_key(state, state.culture_definitions.slaves)); - + rural_population += state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.slaves)); + rural_population += state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.clergy)); auto urban_pop = p.get_demographics(demographics::total) - rural_population; - if(urban_pop < 1000.f) { + if(urban_pop < minimal_population_per_visible_settlement) { continue; } - auto province_size = state.map_state.map_data.province_area[province::to_map_id(p)]; - if(province_size < 1) { + auto province_size = state.map_state.map_data.province_area_km2[province::to_map_id(p)]; + auto province_size_pixels = state.map_state.map_data.province_area[province::to_map_id(p)]; + if(province_size_pixels < 1) { continue; } @@ -2404,7 +2411,17 @@ void display_data::update_sprawl(sys::state& state) { std::vector> weighted_settlements; - int potential_settlement_slots = std::min((unsigned)7, province_size / 200); + auto km2_per_potential_settlement = 2000.f; + + + int potential_settlement_slots = std::min( + (int)7, std::min( + (int)(province_size / km2_per_potential_settlement), + (int)(urban_pop / minimal_population_per_visible_settlement) + ) + ); + potential_settlement_slots = std::max(1, potential_settlement_slots); + int settlement_slots = potential_settlement_slots; if(p.get_port_to()) { @@ -2421,7 +2438,7 @@ void display_data::update_sprawl(sys::state& state) { } } - auto side = sqrt(province_size); + auto side = sqrt(province_size_pixels); // try to spawn random settlements in this area @@ -2446,7 +2463,7 @@ void display_data::update_sprawl(sys::state& state) { settlement_slots -= 1; weighted_settlements.push_back({ pos, 0.5f / (potential_settlement_slots + 1) }); roads.push_back({ pos, central_settlement }); - if(settlement_slots < 0) { + if(settlement_slots <= 0) { break; } } @@ -2527,10 +2544,10 @@ void display_data::update_sprawl(sys::state& state) { continue; } - auto node_1 = get_node(state, settlement.first, i, k); - auto node_2 = get_node(state, settlement.first, i + 1, k); - auto node_3 = get_node(state, settlement.first, i, k + 1); - auto node_4 = get_node(state, settlement.first, i + 1, k + 1); + auto node_1 = get_node(state, settlement.first, i, k, size_x, size_y); + auto node_2 = get_node(state, settlement.first, i + 1, k, size_x, size_y); + auto node_3 = get_node(state, settlement.first, i, k + 1, size_x, size_y); + auto node_4 = get_node(state, settlement.first, i + 1, k + 1, size_x, size_y); auto node_center = (node_1 + node_2 + node_3 + node_4) / 4.f; diff --git a/src/map/map.hpp b/src/map/map.hpp index c8e7f8265..9de570eff 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -195,6 +195,7 @@ class display_data { std::vector terrain_id_map; std::vector median_terrain_type; std::vector province_area; + std::vector province_area_km2; std::vector diagonal_borders; // map pixel -> province id diff --git a/src/map/map_data_loading.cpp b/src/map/map_data_loading.cpp index 687179dd0..37ae6b86f 100644 --- a/src/map/map_data_loading.cpp +++ b/src/map/map_data_loading.cpp @@ -4,6 +4,7 @@ #include "system_state.hpp" #include "parsers_declarations.hpp" #include "opengl_wrapper.hpp" +#include "math_fns.hpp" #ifdef _WIN64 @@ -474,14 +475,35 @@ void display_data::load_terrain_data(parsers::scenario_building_context& context void display_data::load_median_terrain_type(parsers::scenario_building_context& context) { median_terrain_type.resize(context.state.world.province_size() + 1); province_area.resize(context.state.world.province_size() + 1); + province_area_km2.resize(context.state.world.province_size() + 1); + + float R = context.state.defines.alice_globe_mean_radius_km; +#ifndef NDEBUG + float total = 0.f; +#endif std::vector> terrain_histogram(context.state.world.province_size() + 1, std::array{}); for(int i = size_x * size_y - 1; i-- > 0;) { auto prov_id = province_id_map[i]; auto terrain_id = terrain_id_map[i]; if(terrain_id < 64) terrain_histogram[prov_id][terrain_id] += 1; + auto x = i % size_x; + auto y = i / size_x; + // 0.5f is added to shift us to the center of the pixel; + // float s = (((float)x + 0.5f) / (float) size_x) * 2 * math::pi; + float t = (((float)y + 0.5f) / (float) size_y - 0.5f) * math::pi; + auto area_form = R * R * math::cos(t); + auto pixel_size = area_form * (1.f / (float)size_y * math::pi) * (1.f / (float)size_x * 2 * math::pi); + province_area_km2[prov_id] += pixel_size; +#ifndef NDEBUG + total += pixel_size; +#endif } +#ifndef NDEBUG + OutputDebugStringA(("total area of globe is " + std::to_string(total) + "\n").c_str()); +#endif + for(int i = context.state.world.province_size(); i-- > 1;) { // map-id province 0 == the invalid province; we don't need to collect data for it int max_index = 64; int max = 0; diff --git a/src/parsing/defines.hpp b/src/parsing/defines.hpp index 3423ee98f..b85364977 100644 --- a/src/parsing/defines.hpp +++ b/src/parsing/defines.hpp @@ -742,6 +742,8 @@ LUA_DEFINES_LIST_ELEMENT(alice_naval_base_to_colonial_distance_factor, 0.04) \ LUA_DEFINES_LIST_ELEMENT(alice_allow_factories_in_colonies, 0.0) \ LUA_DEFINES_LIST_ELEMENT(alice_always_available_cbs_zero_infamy, 1.0) \ + LUA_DEFINES_LIST_ELEMENT(alice_globe_mean_radius_km, 6371.0) \ + // scales the needs values so that they are needs per this many pops // this value was arrived at by looking at farmers: 40'000 farmers produces enough grain to satisfy about 2/3 From 45c7b55212c3806184cb4ffc7505f83a90c3083b Mon Sep 17 00:00:00 2001 From: ineveraskedforthis Date: Sat, 7 Jun 2025 01:35:54 +0300 Subject: [PATCH 2/2] remove debug --- src/map/map_data_loading.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/map/map_data_loading.cpp b/src/map/map_data_loading.cpp index 37ae6b86f..e8b06c7d5 100644 --- a/src/map/map_data_loading.cpp +++ b/src/map/map_data_loading.cpp @@ -478,9 +478,7 @@ void display_data::load_median_terrain_type(parsers::scenario_building_context& province_area_km2.resize(context.state.world.province_size() + 1); float R = context.state.defines.alice_globe_mean_radius_km; -#ifndef NDEBUG - float total = 0.f; -#endif + std::vector> terrain_histogram(context.state.world.province_size() + 1, std::array{}); for(int i = size_x * size_y - 1; i-- > 0;) { auto prov_id = province_id_map[i]; @@ -495,15 +493,8 @@ void display_data::load_median_terrain_type(parsers::scenario_building_context& auto area_form = R * R * math::cos(t); auto pixel_size = area_form * (1.f / (float)size_y * math::pi) * (1.f / (float)size_x * 2 * math::pi); province_area_km2[prov_id] += pixel_size; -#ifndef NDEBUG - total += pixel_size; -#endif } -#ifndef NDEBUG - OutputDebugStringA(("total area of globe is " + std::to_string(total) + "\n").c_str()); -#endif - for(int i = context.state.world.province_size(); i-- > 1;) { // map-id province 0 == the invalid province; we don't need to collect data for it int max_index = 64; int max = 0;