Skip to content

Commit

Permalink
Merge pull request #1871 from ineveraskedforthis/bug-tax-collection
Browse files Browse the repository at this point in the history
Fix bugs with tax prediction.
  • Loading branch information
schombert authored Jan 20, 2025
2 parents f2ea6ea + 94d8b66 commit 44fdd9d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 101 deletions.
156 changes: 60 additions & 96 deletions src/economy/economy_government.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ namespace economy {
//
// employed people in administration influence the maximum amount of taxes the nation can collect

// to avoid death traps
inline constexpr float base_tax_collection_capacity = 5000.f;

inline constexpr float base_population_per_admin = 50.f;

float population_per_admin(sys::state& state, dcon::nation_id n) {
return base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));
}

inline constexpr float base_admin_employment = 500.f;
inline constexpr float base_tax_collection = 10000.f;

Expand All @@ -31,10 +39,16 @@ inline constexpr float base_tax_collection = 10000.f;

inline constexpr float tax_collection_multiplier = 10.f;

float required_labour_in_capital_administration(sys::state& state, dcon::nation_id n) {
auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));
auto total_population = state.world.nation_get_demographics(n, demographics::total);
return total_population / admin_efficiency + base_admin_employment;
}

float tax_collection_capacity(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid) {
auto local_market = state.world.state_instance_get_market_from_local_market(sid);
auto tax_collection_global = 1.f + global_admin_ratio(state, n);
auto local_tax_collectors = state.world.nation_get_administration_employment_target_in_capital(n)
auto local_tax_collectors = state.world.market_get_administration_employment_target(local_market)
* state.world.market_get_labor_demand_satisfaction(local_market, economy::labor::high_education);

auto collection_rate_per_tax_collector =
Expand All @@ -48,6 +62,9 @@ float tax_collection_capacity(sys::state& state, dcon::nation_id n, dcon::state_
+ float(state.world.nation_get_rich_tax(n));

return
base_tax_collection_capacity
* collection_rate_per_tax_collector
+
tax_collection_global
* (1.f + state.world.nation_get_administrative_efficiency(n))
* nations::tax_efficiency(state, n)
Expand All @@ -62,14 +79,7 @@ float global_admin_ratio(sys::state& state, dcon::nation_id n) {
auto capital_state = state.world.province_get_state_membership(capital);
auto capital_market = state.world.state_instance_get_market_from_local_market(capital_state);

auto total_budget = std::max(0.f, state.world.nation_get_stockpiles(n, economy::money));
auto admin_budget = total_budget * state.world.nation_get_spending_level(n) * float(state.world.nation_get_administrative_spending(n)) / 100.f;

auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));

auto total_population = state.world.nation_get_demographics(n, demographics::total);
auto required_labor_capital = total_population / admin_efficiency + base_admin_employment;

auto required_labor_capital = required_labour_in_capital_administration(state, n);
auto current_labor_capital =
state.world.nation_get_administration_employment_target_in_capital(n)
* state.world.market_get_labor_demand_satisfaction(capital_market, economy::labor::high_education_and_accepted);
Expand All @@ -79,33 +89,23 @@ float global_admin_ratio(sys::state& state, dcon::nation_id n) {

float local_admin_ratio(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid) {
auto local_market = state.world.state_instance_get_market_from_local_market(sid);
auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));

auto local_population = state.world.state_instance_get_demographics(sid, demographics::total);
float required_labor_local = local_population / admin_efficiency;
float required_labor_local = local_population / population_per_admin(state, n);

auto current_labor_local =
state.world.nation_get_administration_employment_target_in_capital(n)
state.world.market_get_administration_employment_target(local_market)
* state.world.market_get_labor_demand_satisfaction(local_market, economy::labor::high_education);

return current_labor_local / required_labor_local;
}

float required_labour_in_capital_administration(sys::state& state, dcon::nation_id n, float budget_priority) {
auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));
auto total_population = state.world.nation_get_demographics(n, demographics::total);
return total_population / admin_efficiency;
}

float estimate_spendings_administration_capital(sys::state& state, dcon::nation_id n, float budget_priority) {
auto total_budget = std::max(0.f, state.world.nation_get_stockpiles(n, economy::money));
auto admin_budget = total_budget * budget_priority;
auto capital = state.world.nation_get_capital(n);
auto capital_state = state.world.province_get_state_membership(capital);
auto capital_market = state.world.state_instance_get_market_from_local_market(capital_state);
auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));
auto total_population = state.world.nation_get_demographics(n, demographics::total);
auto required_labor_capital = total_population / admin_efficiency + base_admin_employment;
auto required_labor_capital = required_labour_in_capital_administration(state, n);
auto labor_price_capital = state.world.market_get_labor_price(capital_market, economy::labor::high_education_and_accepted);
float required_budget = required_labor_capital * labor_price_capital * state.world.market_get_labor_demand_satisfaction(capital_market, labor::high_education_and_accepted);

Expand All @@ -114,11 +114,8 @@ float estimate_spendings_administration_capital(sys::state& state, dcon::nation_

float estimate_spendings_administration_state(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid, float budget_priority) {
auto local_market = state.world.state_instance_get_market_from_local_market(sid);

auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));

auto local_population = state.world.state_instance_get_demographics(sid, demographics::total);
float required_labor_local = local_population / admin_efficiency;
float required_labor_local = local_population / population_per_admin(state, n);
float labor_price_local = state.world.market_get_labor_price(local_market, economy::labor::high_education);

return
Expand All @@ -128,31 +125,12 @@ float estimate_spendings_administration_state(sys::state& state, dcon::nation_id
}

float estimate_spendings_administration(sys::state& state, dcon::nation_id n, float budget_priority) {
auto capital = state.world.nation_get_capital(n);
auto capital_state = state.world.province_get_state_membership(capital);
auto capital_market = state.world.state_instance_get_market_from_local_market(capital_state);

auto total_budget = std::max(0.f, state.world.nation_get_stockpiles(n, economy::money));
auto admin_budget = total_budget * budget_priority;

auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));

auto total_population = state.world.nation_get_demographics(n, demographics::total);
auto required_labor_capital = total_population / admin_efficiency + base_admin_employment;
auto labor_price_capital = state.world.market_get_labor_price(capital_market, economy::labor::high_education_and_accepted);
float required_budget = required_labor_capital * labor_price_capital * state.world.market_get_labor_demand_satisfaction(capital_market, labor::high_education_and_accepted);

float required_budget = estimate_spendings_administration_capital(state, n, budget_priority);
state.world.nation_for_each_state_ownership(n, [&](auto soid) {
auto local_state = state.world.state_ownership_get_state(soid);
auto local_market = state.world.state_instance_get_market_from_local_market(local_state);

auto local_population = state.world.state_instance_get_demographics(local_state, demographics::total);

float required_labor_local = local_population / admin_efficiency;
float labor_price_local = state.world.market_get_labor_price(local_market, economy::labor::high_education);
required_budget += required_labor_local * labor_price_local * state.world.market_get_labor_demand_satisfaction(local_market, labor::high_education);
required_budget += estimate_spendings_administration_state(state, n, state.world.state_ownership_get_state(soid), budget_priority);
});

return std::min(required_budget, admin_budget);
}

Expand All @@ -165,19 +143,17 @@ float full_spendings_administration(sys::state& state, dcon::nation_id n) {
auto total_budget = std::max(0.f, state.world.nation_get_stockpiles(n, economy::money));
auto admin_budget = total_budget * float(state.world.nation_get_administrative_spending(n)) / 100.f;

auto labor_in_capital =
total_cost +=
state.world.nation_get_administration_employment_target_in_capital(n)
* state.world.market_get_labor_demand_satisfaction(capital_market, economy::labor::high_education_and_accepted);

total_cost += labor_in_capital * state.world.market_get_labor_price(capital_market, economy::labor::high_education_and_accepted);
* state.world.market_get_labor_demand_satisfaction(capital_market, economy::labor::high_education_and_accepted)
* state.world.market_get_labor_price(capital_market, economy::labor::high_education_and_accepted);

state.world.nation_for_each_state_ownership(n, [&](auto soid) {
auto local_state = state.world.state_ownership_get_state(soid);
auto local_market = state.world.state_instance_get_market_from_local_market(local_state);

float target = state.world.market_get_administration_employment_target(local_market);
total_cost +=
target
state.world.market_get_administration_employment_target(local_market)
* state.world.market_get_labor_demand_satisfaction(local_market, labor::high_education)
* state.world.market_get_labor_price(local_market, labor::high_education);
});
Expand All @@ -197,8 +173,7 @@ void update_consumption_administration(sys::state& state, dcon::nation_id n) {

auto admin_efficiency = base_population_per_admin * (1.f + state.world.nation_get_administrative_efficiency(n));

auto total_population = state.world.nation_get_demographics(n, demographics::total);
auto required_labor_capital = total_population / admin_efficiency + base_admin_employment;
auto required_labor_capital = required_labour_in_capital_administration(state, n);
auto labor_price_capital = state.world.market_get_labor_price(capital_market, economy::labor::high_education_and_accepted);
auto effective_demand = std::min(required_labor_capital, admin_budget / labor_price_capital);

Expand Down Expand Up @@ -247,8 +222,6 @@ void update_consumption_administration(sys::state& state, dcon::nation_id n) {
}

void collect_taxes(sys::state& state, dcon::nation_id n) {
auto const tax_eff = nations::tax_efficiency(state, n);

float total_poor_tax_base = 0.0f;
float total_mid_tax_base = 0.0f;
float total_rich_tax_base = 0.0f;
Expand All @@ -263,6 +236,10 @@ void collect_taxes(sys::state& state, dcon::nation_id n) {
float potential_tax_rich = 0.f;

province::for_each_province_in_state_instance(state, s, [&](auto province) {
float province_potential_tax_poor = 0.f;
float province_potential_tax_mid = 0.f;
float province_potential_tax_rich = 0.f;

if(
state.world.province_get_nation_from_province_ownership(province)
==
Expand All @@ -272,35 +249,42 @@ void collect_taxes(sys::state& state, dcon::nation_id n) {
auto& pop_money = pl.get_pop().get_savings();
auto strata = culture::pop_strata(pl.get_pop().get_poptype().get_strata());
if(strata == culture::pop_strata::poor) {
potential_tax_poor += pop_money;
province_potential_tax_poor += pop_money;
} else if(strata == culture::pop_strata::middle) {
potential_tax_mid += pop_money;
province_potential_tax_mid += pop_money;
} else if(strata == culture::pop_strata::rich) {
potential_tax_rich += pop_money;
province_potential_tax_rich += pop_money;
}
assert(std::isfinite(pl.get_pop().get_savings()));
}
}

state.world.province_set_tax_base_poor(province, province_potential_tax_poor);
state.world.province_set_tax_base_middle(province, province_potential_tax_mid);
state.world.province_set_tax_base_rich(province, province_potential_tax_rich);

potential_tax_poor += province_potential_tax_poor;
potential_tax_mid += province_potential_tax_mid;
potential_tax_rich += province_potential_tax_rich;
});

total_poor_tax_base += potential_tax_poor;
total_mid_tax_base += potential_tax_mid;
total_rich_tax_base += potential_tax_rich;


float local_target_tax = std::min(
potential_tax_poor * float(state.world.nation_get_poor_tax(n)) / 100.f
auto local_tax = potential_tax_poor * float(state.world.nation_get_poor_tax(n)) / 100.f
+ potential_tax_mid * float(state.world.nation_get_middle_tax(n)) / 100.0f
+ potential_tax_rich * float(state.world.nation_get_rich_tax(n)) / 100.0f,
max_tax_capacity
);
+ potential_tax_rich * float(state.world.nation_get_rich_tax(n)) / 100.0f;
auto total_possible = std::min(local_tax, max_tax_capacity);

auto collected_ratio = 1.f;
if(local_target_tax > 0.f) {
collected_ratio = std::min(local_target_tax, max_tax_capacity) / local_target_tax;

auto collected_ratio = 0.f;
if(total_possible > 0.f) {
collected_ratio = total_possible / local_tax;
}

collected_tax += std::min(local_target_tax, max_tax_capacity);
collected_tax += local_tax * collected_ratio;

// apply actual tax

Expand Down Expand Up @@ -350,44 +334,24 @@ void collect_taxes(sys::state& state, dcon::nation_id n) {

tax_information explain_tax_income_local(sys::state& state, dcon::nation_id n, dcon::state_instance_id s) {
tax_information result{ };

result.capacity = tax_collection_capacity(state, n, s);

province::for_each_province_in_state_instance(state, s, [&](auto province) {
if(
state.world.province_get_nation_from_province_ownership(province)
==
state.world.province_get_nation_from_province_control(province)
) {
for(auto pl : state.world.province_get_pop_location(province)) {
auto& pop_money = pl.get_pop().get_savings();
auto strata = culture::pop_strata(pl.get_pop().get_poptype().get_strata());
if(strata == culture::pop_strata::poor) {
result.poor_potential += pop_money;
} else if(strata == culture::pop_strata::middle) {
result.mid_potential += pop_money;
} else if(strata == culture::pop_strata::rich) {
result.rich_potential += pop_money;
}
assert(std::isfinite(pl.get_pop().get_savings()));
}
}
result.poor_potential += state.world.province_get_tax_base_poor(province);
result.mid_potential += state.world.province_get_tax_base_middle(province);
result.rich_potential += state.world.province_get_tax_base_rich(province);
});

result.poor = result.poor_potential * float(state.world.nation_get_poor_tax(n)) / 100.f;
result.mid = result.mid_potential * float(state.world.nation_get_middle_tax(n)) / 100.0f;
result.rich = result.rich_potential * float(state.world.nation_get_rich_tax(n)) / 100.0f;
auto total = result.poor + result.mid + result.rich;

auto collected_ratio = 1.f;
if(total > 0.f) {
collected_ratio = std::min(total, result.capacity) / total;
auto total_possible = std::min(total, result.capacity);
auto collected_ratio = 0.f;
if(total_possible > 0.f) {
collected_ratio = total_possible / total;
}

result.poor *= collected_ratio;
result.mid *= collected_ratio;
result.rich *= collected_ratio;

return result;
}

Expand Down
17 changes: 17 additions & 0 deletions src/gamestate/dcon_generated.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,23 @@ object {
name{ rgo_actual_production_per_good }
type{ array{commodity_id}{float} }
}

property{
name{ tax_base_poor }
type{ float }
tag{ save }
}
property{
name{ tax_base_middle }
type{ float }
tag{ save }
}
property{
name{ tax_base_rich }
type{ float }
tag{ save }
}

property{
name{ daily_net_migration }
type{ float }
Expand Down
12 changes: 7 additions & 5 deletions src/gui/budgetwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3173,12 +3173,14 @@ void budgetwindow_main_expenses_table_t::on_update(sys::state& state) noexcept {
state.world.nation_for_each_state_ownership(state.local_player_nation, [&](auto soid) {
auto local_state = state.world.state_ownership_get_state(soid);
auto market = state.world.state_instance_get_market_from_local_market(local_state);
float total = economy::estimate_spendings_administration_state(
state, state.local_player_nation, local_state, fraction
add_value(
std::pair<std::string, float>(
text::get_dynamic_state_name(state, local_state),
economy::estimate_spendings_administration_state(
state, state.local_player_nation, local_state, fraction
)
)
);
if(total > 0.0f) {
add_value(std::pair<std::string, float>(text::get_dynamic_state_name(state, local_state), total * fraction));
}
});
add_insert_bottom_spacer(state);
} else {
Expand Down

0 comments on commit 44fdd9d

Please sign in to comment.