diff --git a/assets/alice.gfx b/assets/alice.gfx index 8aec55a42..be556382f 100644 --- a/assets/alice.gfx +++ b/assets/alice.gfx @@ -636,6 +636,6 @@ spriteTypes = { spriteType = { name = "provincetiles" texturefile = "assets\\provincetiles.png" - noOfFrames = 15 + noOfFrames = 22 } } diff --git a/assets/localisation/en-US/alice.csv b/assets/localisation/en-US/alice.csv index 56e313f69..95a0ba3d2 100644 --- a/assets/localisation/en-US/alice.csv +++ b/assets/localisation/en-US/alice.csv @@ -1,3 +1,4 @@ +PROVINCEVIEW_GOODSINCOME;Sold ?Y$x$?W ?Y$GOODS$?W for ?Y$VALUE$?W yesterday support_for_blank;support for $text$ uh_support_for_blank;upper house support for $text$ up_to;up to @@ -377,6 +378,30 @@ has_not_recently_lost_war;has not recently lost a war mobilized;mobilized mobilization_size;mobilization size admin_spending;administration spending +employment_type_no_education;Employment type: ?YNo education?W +employment_type_basic_education;Employment type: ?YBasic education?W +employment_type_high_education_and_accepted;Employment type: ?YHigh Education and Accepted?W +employment_type_high_education;Employment type: ?YHigh Education?W +alice_trade_attractiveness;Trade Route Attraction +trade_center;Trade Centre +trade_center_desc;Trade Centres manage trade inside the market and between state-level markets, buying goods up to desired stockpile and selling extras to neighbours. +trade_center_employment;Trade Center Employees: ?Y$value$?W +trade_centre_max_throughput;Max throughput: ?Y$value$?W +local_admin;Local Administration +capital_admin;Capital Administration +local_admin_spending;Estimated cost: ?Y$value$?W +local_admin_employment;Administration Employees: ?Y$value$?W +target_employment;Target employment: ?Y$value$?W +employment_satisfaction;Employment satisfaction: ?Y$value$?W +wage;Wage: ?Y$value$?W +local_admin_efficiency;Local administrations are ?Y$value$?W less efficient than the capital one. +tax_collection_rate;Tax collection rate: ?Y$value$?W +poor_potential;Potential poor taxes: ?Y$value$?W +mid_potential;Potential middle taxes: ?Y$value$?W +rich_potential;Potential rich taxes: ?Y$value$?W +poor_taxes;Actual poor taxes: ?Y$value$?W +mid_taxes;Actual middle taxes: ?Y$value$?W +rich_taxes;Actual rich taxes: ?Y$value$?W greater_than_edu_spending;greater than education spending support_for_rp;support for ruling party colonial;colonial @@ -517,9 +542,10 @@ factory_upgrade_condition_11;State has available resource potentials factory_delete_header;Delete factory factory_delete_not_allowed;The ruling party does not allow us to delete factories factory_level;Factory level ?Y$val$ -factory_stats_1;This factory is currently operating at $val$ capacity -factory_stats_2;This factory is targeting $val$ capacity -factory_stats_3;It produced $val$ units of $x$ in the previous day +factory_employment;Factory employees: ?Y$val$ +factory_stats_1;Current production scale: ?Y$val$?W +factory_stats_2;Target production scale: ?Y$val$?W +factory_stats_3;Yesterday it produced ?Y$val$ $good$?W sold for ?Y$x$?W factory_stats_4;It made a profit of $val$ in the previous day factory_stats_5;Inputs availability: factory_stats_6;Efficiency inputs availability: @@ -1185,7 +1211,11 @@ alice_spending_commodity_2;?R$cost$?W - Buying $need$ of $name$ (at $val$ x unit alice_recommended_build;?GThis factory is recommended to be built?W alice_factory_bonus;We will receive a ?Y$x$?W bonus if: alice_factory_inputs;Inputs required: -alice_factory_construction_cost;Construction cost: +alice_construction_cost;Construction cost: +alice_building_modifier;Building gives the following effect: +alice_new_building_modifier;Building will give the following effect: +alice_building_level;Building Level: ?Y$val$?W +alice_building_conditions;To build, the following must be true: alice_factory_construction_explain_3;Purchased goods worth: ?Y$x$?W alice_factory_construction_explain_4;Total estimated price: ?Y$x$?W alice_factory_construction_explain_5;Progress: ?Y$x$?W @@ -1419,6 +1449,14 @@ trade_route_volume_base_change;Base expected change: ?Y$val$?W (Current volume ? trade_route_volume_expansion_multiplier;Expansion multiplier: ?Y$val$?W (Depends on actual access to commodity in exporting market) trade_route_volume_decay;Decay: ?Y$val$?W (Prevents trade volume from running too far away) trade_route_volume_final_change;Expected change: ?Y$val$ +trade_centre_trade_volume;Trade volume: ?Y$val$ +trade_centre_trade_value;Trade value: ?Y$val$ +trade_centre_imports_volume;Imports volume: ?Y$val$ +trade_centre_imports_value;Imports value: ?Y$val$ +trade_centre_exports_volume;Exports volume: ?Y$val$ +trade_centre_exports_value;Exports value: ?Y$val$ +trade_centre_trade_routes_profit;Profit from trade routes: ?Y$val$ +trade_centre_money;Money stockpile: ?Y$val$ investment_pool;Investment pool: ?Y$x$?W investment_pool_income_1;Population reinvestment: ?G$x$?W investment_pool_income_2;Transfer from subject $country$: ?G$x$?W @@ -1551,6 +1589,8 @@ pop_migration_attraction_3;The migration target factor: $x$ pop_migration_attraction_wage_ratio;And the wage difference multipler: $x$ pop_migration_attraction_bureaucracy;Bureaucracy base attraction: $x$ alice_toggle_administration;Establish or abolish local administration. Administrations outside your control will not work. Consult administrative map mode to check existing administrations. +administration_tile;Local administration +market_tile;Local market alice_unit_target;===> $x$ alice_lobby_resync;Resync lobby alice_lobby_resync_players_loading;Cannot resync when players are loading diff --git a/assets/localisation/zh-CN/alice.csv b/assets/localisation/zh-CN/alice.csv index f52fa0dde..f7447d202 100644 --- a/assets/localisation/zh-CN/alice.csv +++ b/assets/localisation/zh-CN/alice.csv @@ -1532,7 +1532,7 @@ CANBUILD_FORCEDISARM;国家尚未解除武装。 alice_naval_coordination_penalty;$x$ 因超过敌舰规模而受到 ?R$y$?W 的海军协调惩罚,使其目标选择减少了 ?R$val$?W 。 alice_naval_coordination_bonus;$x$ 因低于敌舰规模而受到 ?R$y$?W 的海军协调加成,使其目标选择增加了 ?R$val$?W 。 alice_naval_stacking_penalty;$x$ 因堆叠惩罚而受到 ?R$val$?W 的伤害倍增。 -alice_factory_construction_cost;施工成本: +alice_construction_cost;施工成本: alice_factory_construction_explain_3;购买的商品价值:?Y$x$?W alice_factory_construction_explain_4;估计总价:?Y$x$?W alice_factory_construction_explain_5;进展:?Y$x$?W diff --git a/assets/provincetiles.png b/assets/provincetiles.png index 913531ea3..204783d30 100644 Binary files a/assets/provincetiles.png and b/assets/provincetiles.png differ diff --git a/src/economy/economy.hpp b/src/economy/economy.hpp index 9a508dd41..03de11301 100644 --- a/src/economy/economy.hpp +++ b/src/economy/economy.hpp @@ -164,6 +164,7 @@ bool is_bankrupt_debtor_to(sys::state& state, dcon::nation_id debt_holder, dcon: // abstract modifiers float factory_total_desired_employment_score(sys::state const& state, dcon::factory_id f); +float factory_total_desired_employment(sys::state const& state, dcon::factory_id f); float factory_total_employment(sys::state const& state, dcon::factory_id f); float factory_unqualified_employment(sys::state const& state, dcon::factory_id f); float factory_primary_employment(sys::state const& state, dcon::factory_id f); diff --git a/src/economy/economy_government.cpp b/src/economy/economy_government.cpp index b19fa0a21..9968a79ec 100644 --- a/src/economy/economy_government.cpp +++ b/src/economy/economy_government.cpp @@ -137,7 +137,7 @@ void update_consumption_administration(sys::state& state, dcon::nation_id n) { auto wage = state.world.province_get_labor_price(capital_of_capital_state, economy::labor::high_education_and_accepted); auto demand = budget_per_administration / wage; auto sat = state.world.province_get_labor_demand_satisfaction(capital_of_capital_state, economy::labor::high_education_and_accepted); - state.world.province_get_control_scale(capital) += std::max(0.f, (demand * sat - base_admin_employment) * population_per_admin(state, n) * 0.5f); + state.world.province_get_control_scale(capital) += std::max(0.f, (demand * sat - base_admin_employment) * population_per_admin(state, n) * local_administration_efficiency); state.world.province_set_administration_employment_target(capital_of_capital_state, demand); state.world.province_get_labor_demand(capital_of_capital_state, economy::labor::high_education_and_accepted) += demand; }); @@ -268,4 +268,30 @@ tax_information explain_tax_income(sys::state& state, dcon::nation_id n) { return result; } +// Calculate employment of local administrations in the province. +// When using, check for capital administration separately +float explain_administration_employment(sys::state& state, dcon::province_id p) { + auto n = state.world.province_get_nation_from_province_ownership(p); + + for(auto admin : state.world.nation_get_nation_administration(n)) { + if(admin.get_administration().get_capital() == p) { + return state.world.province_get_administration_employment_target(p) * state.world.province_get_labor_demand_satisfaction(p, economy::labor::high_education_and_accepted); + } + } + + return 0.f; +} + +// Calculate employment of the capital administration +float explain_capital_administration_employment(sys::state& state, dcon::nation_id n) { + auto capital = state.world.nation_get_capital(n); + auto capital_state = state.world.province_get_state_membership(capital); + auto capital_of_capital_state = state.world.state_instance_get_capital(capital_state); + + auto target_employment = state.world.nation_get_administration_employment_target_in_capital(n); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(capital, economy::labor::high_education_and_accepted); + + return target_employment * satisfaction; +} + } diff --git a/src/economy/economy_government.hpp b/src/economy/economy_government.hpp index e54ad071f..010b97f16 100644 --- a/src/economy/economy_government.hpp +++ b/src/economy/economy_government.hpp @@ -6,6 +6,9 @@ struct state; } namespace economy { + +inline constexpr float local_administration_efficiency = 0.5f; + // see details about internal workings of the system in cpp file // ratio of taxes you can collect in a given province @@ -39,4 +42,6 @@ struct tax_information { // sums up all tax income all over the nation tax_information explain_tax_income(sys::state& state, dcon::nation_id n); tax_information explain_tax_income_local(sys::state& state, dcon::nation_id n, dcon::province_id sid); +float explain_administration_employment(sys::state& state, dcon::province_id p); +float explain_capital_administration_employment(sys::state& state, dcon::nation_id n); } diff --git a/src/economy/economy_trade_routes.cpp b/src/economy/economy_trade_routes.cpp index cdd8f4638..e847b6528 100644 --- a/src/economy/economy_trade_routes.cpp +++ b/src/economy/economy_trade_routes.cpp @@ -8,6 +8,82 @@ namespace economy { +// Labour demand for a single trade route +float trade_route_labour_demand(sys::state& state, dcon::trade_route_id trade_route, dcon::province_fat_id A_capital, dcon::province_fat_id B_capital) { + auto total_demanded_labor = 0.f; + auto available_labor = std::min( + state.world.province_get_labor_demand_satisfaction(A_capital, labor::no_education), + state.world.province_get_labor_demand_satisfaction(B_capital, labor::no_education) + ); + + state.world.for_each_commodity([&](auto cid) { + auto current_volume = state.world.trade_route_get_volume(trade_route, cid); + if(current_volume == 0.f) { + return; + } + current_volume = current_volume * std::max(0.999999f, available_labor); + state.world.trade_route_set_volume(trade_route, cid, current_volume); + auto effect_of_scale = std::max( + trade_effect_of_scale_lower_bound, + 1.f - std::abs(current_volume) * effect_of_transportation_scale + ); + total_demanded_labor += std::abs(current_volume) + * state.world.trade_route_get_distance(trade_route) + / trade_distance_covered_by_pair_of_workers_per_unit_of_good + * effect_of_scale; + assert(std::isfinite(total_demanded_labor)); + }); + + return total_demanded_labor; +} + +// Calculate labour demand for trade routes between markets +float transportation_between_markets_labor_demand(sys::state& state, dcon::market_id market) { + + auto total_demanded_labour = 0.f; + + for(auto route : state.world.market_get_trade_route(market)) { + auto A = state.world.trade_route_get_connected_markets(route, 0); + auto B = state.world.trade_route_get_connected_markets(route, 1); + + auto A_capital = state.world.state_instance_get_capital(state.world.market_get_zone_from_local_market(A)); + auto B_capital = state.world.state_instance_get_capital(state.world.market_get_zone_from_local_market(B)); + + total_demanded_labour += trade_route_labour_demand(state, route, A_capital, B_capital); + } + + return total_demanded_labour; +} + + +// Calculate labour demand for trade inside the market +float transportation_inside_market_labor_demand(sys::state& state, dcon::market_id market, dcon::province_id capital) { + auto base_cargo_transport_demand = 0.f; + + state.world.for_each_commodity([&](auto commodity) { + state.world.market_for_each_trade_route(market, [&](auto trade_route) { + auto current_volume = state.world.trade_route_get_volume(trade_route, commodity); + auto origin = + current_volume > 0.f + ? state.world.trade_route_get_connected_markets(trade_route, 0) + : state.world.trade_route_get_connected_markets(trade_route, 1); + auto target = + current_volume <= 0.f + ? state.world.trade_route_get_connected_markets(trade_route, 0) + : state.world.trade_route_get_connected_markets(trade_route, 1); + + //auto sat = state.world.market_get_direct_demand_satisfaction(origin, commodity); + base_cargo_transport_demand += std::abs(current_volume); + }); + }); + + // auto soft_transport_demand_limit = state.world.market_get_max_throughput(market); + //if(base_cargo_transport_demand > soft_transport_demand_limit) { + // base_cargo_transport_demand = base_cargo_transport_demand * base_cargo_transport_demand / soft_transport_demand_limit; + //} + + return base_cargo_transport_demand; +} tariff_data explain_trade_route(sys::state& state, dcon::trade_route_id trade_route) { auto m0 = state.world.trade_route_get_connected_markets(trade_route, 0); @@ -76,6 +152,50 @@ tariff_data explain_trade_route(sys::state& state, dcon::trade_route_id trade_ro }; } +void make_trade_center_tooltip(sys::state& state, text::columnar_layout& contents, dcon::market_id market) { + auto trade_volume = 0.f; + auto trade_value = 0.f; + auto imports_volume = 0.f; + auto imports_value = 0.f; + auto exports_volume = 0.f; + auto exports_value = 0.f; + auto profit = 0.f; + + auto labour_demand = 0.f; + + for(auto commodity : state.world.in_commodity) { + for(auto route : state.world.market_get_trade_route(market)) { + auto explain = explain_trade_route_commodity(state, route, commodity); + + if(market == explain.origin && explain.amount_origin > 0) { + exports_volume += explain.amount_origin; + exports_value += explain.amount_origin * explain.price_origin; + trade_value += explain.amount_origin * explain.price_origin; + trade_volume += explain.amount_origin; + profit += explain.amount_origin * explain.payment_received_per_unit; + } + else if(market == explain.target && explain.amount_target > 0) { + imports_volume += explain.amount_target; + imports_value += explain.amount_target * explain.price_target; + trade_value += explain.amount_target * explain.price_target; + trade_volume += explain.amount_target; + profit -= explain.amount_target * explain.payment_per_unit; + } + } + } + + text::add_line(state, contents, "trade_centre_trade_volume", text::variable_type::val, text::fp_two_places{ trade_volume }); + text::add_line(state, contents, "trade_centre_imports_volume", text::variable_type::val, text::fp_two_places{ imports_volume }, 15); + text::add_line(state, contents, "trade_centre_exports_volume", text::variable_type::val, text::fp_two_places{ exports_volume }, 15); + + text::add_line(state, contents, "trade_centre_trade_value", text::variable_type::val, text::fp_currency{ trade_value }); + text::add_line(state, contents, "trade_centre_imports_value", text::variable_type::val, text::fp_currency{ imports_value }, 15); + text::add_line(state, contents, "trade_centre_exports_value", text::variable_type::val, text::fp_currency{ exports_value }, 15); + + text::add_line(state, contents, "trade_centre_trade_routes_profit", text::variable_type::val, text::fp_currency{ profit }); + text::add_line(state, contents, "trade_centre_money", text::variable_type::val, text::fp_currency{ state.world.market_get_stockpile(market, money) }); +} + void make_trade_volume_tooltip( sys::state& state, text::columnar_layout& contents, @@ -793,35 +913,14 @@ void update_trade_routes_consumption(sys::state& state) { // register trade demand on transportation labor: // money are paid during calculation of trade route profits and actual movement of goods state.world.for_each_trade_route([&](auto trade_route) { + auto A = state.world.trade_route_get_connected_markets(trade_route, 0); auto B = state.world.trade_route_get_connected_markets(trade_route, 1); auto A_capital = state.world.state_instance_get_capital(state.world.market_get_zone_from_local_market(A)); auto B_capital = state.world.state_instance_get_capital(state.world.market_get_zone_from_local_market(B)); - - auto total_demanded_labor = 0.f; - auto available_labor = std::min( - state.world.province_get_labor_demand_satisfaction(A_capital, labor::no_education), - state.world.province_get_labor_demand_satisfaction(B_capital, labor::no_education) - ); - - state.world.for_each_commodity([&](auto cid) { - auto current_volume = state.world.trade_route_get_volume(trade_route, cid); - if(current_volume == 0.f) { - return; - } - current_volume = current_volume * std::max(0.999999f, available_labor); - state.world.trade_route_set_volume(trade_route, cid, current_volume); - auto effect_of_scale = std::max( - trade_effect_of_scale_lower_bound, - 1.f - std::abs(current_volume) * effect_of_transportation_scale - ); - total_demanded_labor += std::abs(current_volume) - * state.world.trade_route_get_distance(trade_route) - / trade_distance_covered_by_pair_of_workers_per_unit_of_good - * effect_of_scale; - assert(std::isfinite(total_demanded_labor)); - }); + + auto total_demanded_labor = trade_route_labour_demand(state, trade_route, A_capital, B_capital); state.world.province_get_labor_demand(A_capital, labor::no_education) += total_demanded_labor; state.world.province_get_labor_demand(B_capital, labor::no_education) += total_demanded_labor; @@ -837,26 +936,9 @@ void update_trade_routes_consumption(sys::state& state) { state.world.for_each_market([&](auto market) { auto capital = state.world.state_instance_get_capital(state.world.market_get_zone_from_local_market(market)); - auto base_cargo_transport_demand = 0.f; - auto soft_transport_demand_limit = state.world.market_get_max_throughput(market); - - state.world.for_each_commodity([&](auto commodity) { - state.world.market_for_each_trade_route(market, [&](auto trade_route) { - auto current_volume = state.world.trade_route_get_volume(trade_route, commodity); - auto origin = - current_volume > 0.f - ? state.world.trade_route_get_connected_markets(trade_route, 0) - : state.world.trade_route_get_connected_markets(trade_route, 1); - auto target = - current_volume <= 0.f - ? state.world.trade_route_get_connected_markets(trade_route, 0) - : state.world.trade_route_get_connected_markets(trade_route, 1); - - //auto sat = state.world.market_get_direct_demand_satisfaction(origin, commodity); - base_cargo_transport_demand += std::abs(current_volume); - }); - }); + auto base_cargo_transport_demand = transportation_inside_market_labor_demand(state, market, capital); + // auto soft_transport_demand_limit = state.world.market_get_max_throughput(market); //if(base_cargo_transport_demand > soft_transport_demand_limit) { // base_cargo_transport_demand = base_cargo_transport_demand * base_cargo_transport_demand / soft_transport_demand_limit; //} diff --git a/src/economy/economy_trade_routes.hpp b/src/economy/economy_trade_routes.hpp index 713f6c432..24f5f90e6 100644 --- a/src/economy/economy_trade_routes.hpp +++ b/src/economy/economy_trade_routes.hpp @@ -49,6 +49,16 @@ struct trade_route_volume_change_reasons { bool commodity_is_not_discovered; }; +float trade_route_labour_demand(sys::state& state, dcon::trade_route_id trade_route, dcon::province_fat_id A_capital, dcon::province_fat_id B_capital); +float transportation_between_markets_labor_demand(sys::state& state, dcon::market_id market); +float transportation_inside_market_labor_demand(sys::state& state, dcon::market_id market, dcon::province_id capital); + +void make_trade_center_tooltip( + sys::state& state, + text::columnar_layout& contents, + dcon::market_id market +); + void make_trade_volume_tooltip( sys::state& state, text::columnar_layout& contents, diff --git a/src/gamestate/commands.cpp b/src/gamestate/commands.cpp index 4642a5d0e..085094c88 100644 --- a/src/gamestate/commands.cpp +++ b/src/gamestate/commands.cpp @@ -2678,12 +2678,14 @@ bool can_switch_embargo_status(sys::state& state, dcon::nation_id asker, dcon::n return true; } void execute_switch_embargo_status(sys::state& state, dcon::nation_id asker, dcon::nation_id target) { - auto& current_diplo = state.world.nation_get_diplomatic_points(asker); - state.world.nation_set_diplomatic_points(asker, current_diplo - state.defines.askmilaccess_diplomatic_cost); + if(state.world.nation_get_is_player_controlled(asker)) { + auto& points = state.world.nation_get_diplomatic_points(asker); + state.world.nation_set_diplomatic_points(asker, points - state.defines.askmilaccess_diplomatic_cost); + } - auto rel_1 = state.world.get_unilateral_relationship_by_unilateral_pair(target, asker); + auto rel_1 = state.world.get_unilateral_relationship_by_unilateral_pair(asker, target); if(!rel_1) { - rel_1 = state.world.force_create_unilateral_relationship(target, asker); + rel_1 = state.world.force_create_unilateral_relationship(asker, target); } state.world.unilateral_relationship_set_embargo(rel_1, !state.world.unilateral_relationship_get_embargo(rel_1)); diff --git a/src/gui/gui_common_elements.hpp b/src/gui/gui_common_elements.hpp index 67a407f55..e96c1a24f 100644 --- a/src/gui/gui_common_elements.hpp +++ b/src/gui/gui_common_elements.hpp @@ -2382,9 +2382,18 @@ inline void province_owner_rgo_commodity_tooltip(sys::state& state, text::column auto mobilization_impact = (state.world.nation_get_is_mobilized(nat_id) ? military::mobilization_impact(state, nat_id) : 1.f); text::add_line(state, contents, "provinceview_goodsincome", text::variable_type::goods, rgo_good.get_name(), text::variable_type::value, - text::fp_currency{ economy::rgo_income(state, prov_id) }); + text::fp_currency{ economy::rgo_income(state, c, prov_id) }, + text::variable_type::x, text::fp_two_places{ economy::rgo_output(state, c, prov_id) }); text::add_line(state, contents, "PROVINCEVIEW_EMPLOYMENT", text::variable_type::value, text::fp_two_places{ economy::rgo_employment(state, rgo_good, prov_id) }); + auto target_employment = state.world.province_get_rgo_target_employment(prov_id, rgo_good); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(prov_id, economy::labor::no_education); + text::add_line(state, contents, "employment_type_no_education", 15); + text::add_line(state, contents, "target_employment", text::variable_type::value, text::fp_one_place{ target_employment }, 15); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 15); + auto wage = state.world.province_get_labor_price(prov_id, economy::labor::no_education); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 15); + text::add_line(state, contents, "provinceview_max_employment", text::variable_type::value, text::fp_two_places{ economy::rgo_max_employment(state, rgo_good, prov_id) }); { auto box = text::open_layout_box(contents, 0); @@ -2504,7 +2513,6 @@ inline void factory_stats_tooltip(sys::state& state, text::columnar_layout& cont ); float effective_production_scale = economy::factory_total_employment_score(state, fid); - auto amount = (0.75f + 0.25f * e_inputs_data.min_available) * inputs_data.min_available * effective_production_scale; text::add_line(state, contents, state.world.factory_type_get_name(type)); @@ -2512,47 +2520,69 @@ inline void factory_stats_tooltip(sys::state& state, text::columnar_layout& cont text::add_line_break_to_layout(state, contents); text::add_line(state, contents, "factory_stats_1", text::variable_type::val, text::fp_percentage{ amount }); + text::add_line(state, contents, "factory_stats_2", text::variable_type::val, text::fp_percentage{ effective_production_scale }); - text::add_line(state, contents, "factory_stats_2", text::variable_type::val, - text::fp_percentage{ economy::factory_total_employment_score(state, fid) }); + auto employment = economy::factory_total_employment(state, fid); + auto target_employment = economy::factory_total_desired_employment(state, fid); + auto profit_explanation = economy::explain_last_factory_profit(state, fid); - text::add_line(state, contents, "factory_stats_3", text::variable_type::val, - text::fp_one_place{ state.world.factory_get_output(fid) }, text::variable_type::x, type.get_output().get_name()); + text::add_line(state, contents, "factory_employment", text::variable_type::value, text::fp_one_place{ employment }); + text::add_line(state, contents, "target_employment", text::variable_type::value, text::fp_one_place{ target_employment }, 15); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ -profit_explanation.wages }, 15); - auto profit_explantion = economy::explain_last_factory_profit(state, fid); - - text::add_line(state, contents, "factory_stats_4", text::variable_type::val, - text::fp_currency{ - profit_explantion.profit - } - ); + { + auto ftte = state.world.factory_get_unqualified_employment(fid); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(p, economy::labor::no_education); + auto wage = state.world.province_get_labor_price(p, economy::labor::no_education); + text::add_line(state, contents, "employment_type_no_education", 30); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 30); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 30); + } { - auto box = text::open_layout_box(contents); - text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explantion.inputs }, text::text_color::red); - text::close_layout_box(contents, box); + auto ftte = state.world.factory_get_primary_employment(fid); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(p, economy::labor::basic_education); + auto wage = state.world.province_get_labor_price(p, economy::labor::basic_education); + + text::add_line(state, contents, "employment_type_basic_education", 30); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 30); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 30); } { - auto box = text::open_layout_box(contents); - text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explantion.maintenance }, text::text_color::red); - text::close_layout_box(contents, box); + auto ftte = state.world.factory_get_secondary_employment(fid); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(p, economy::labor::high_education); + auto wage = state.world.province_get_labor_price(p, economy::labor::high_education); + + text::add_line(state, contents, "employment_type_high_education", 30); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 30); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 30); } + { auto box = text::open_layout_box(contents); - text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explantion.expansion }, text::text_color::red); + text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explanation.inputs }, text::text_color::red); text::close_layout_box(contents, box); } { auto box = text::open_layout_box(contents); - text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explantion.wages }, text::text_color::red); + text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explanation.maintenance }, text::text_color::red); text::close_layout_box(contents, box); } { auto box = text::open_layout_box(contents); - text::add_to_layout_box(state, contents, box, text::fp_currency{ profit_explantion.output }, text::text_color::green); + text::add_to_layout_box(state, contents, box, text::fp_currency{ -profit_explanation.expansion }, text::text_color::red); text::close_layout_box(contents, box); } + text::add_line(state, contents, "factory_stats_3", + text::variable_type::val, text::fp_one_place{ state.world.factory_get_output(fid) }, + text::variable_type::good, type.get_output().get_name(), + text::variable_type::x, text::fp_currency{ profit_explanation.output }); + text::add_line(state, contents, "factory_stats_4", text::variable_type::val, + text::fp_currency{ + profit_explanation.profit + } + ); text::add_line_break_to_layout(state, contents); @@ -2798,7 +2828,7 @@ inline void factory_construction_tooltip(sys::state& state, text::columnar_layou float refit_discount = (fat_fcid.get_refit_target()) ? state.defines.alice_factory_refit_cost_modifier : 1.0f; auto market = state.world.state_instance_get_market_from_local_market(fat_fcid.get_province().get_state_membership()); - text::add_line(state, contents, "alice_factory_construction_cost"); + text::add_line(state, contents, "alice_construction_cost"); // List factory type construction costs for(uint32_t i = 0; i < economy::commodity_set::set_size; ++i) { @@ -2827,5 +2857,123 @@ inline void factory_construction_tooltip(sys::state& state, text::columnar_layou text::add_line(state, contents, "alice_factory_construction_explain_5", text::variable_type::x, text::fp_percentage{ progress }); }; +inline void province_building_effect_tooltip(sys::state& state, text::columnar_layout& contents, dcon::province_id p, economy::province_building_type bt, float level = 1.f) { + auto def = state.economy_definitions.building_definitions[uint8_t(bt)]; + modifier_description(state, contents, state.economy_definitions.building_definitions[uint8_t(bt)].province_modifier, 0, level); + // Since trade accounts for naval bases level separately, show special case for trade attractiveness for them + if(bt == economy::province_building_type::naval_base) { + auto box = text::open_layout_box(contents, 0); + text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "alice_trade_attractiveness"), text::text_color::white); + text::add_to_layout_box(state, contents, box, std::string_view{ ":" }, text::text_color::white); + text::add_space_to_layout_box(state, contents, box); + text::add_to_layout_box(state, contents, box, text::fp_percentage{ nations::naval_base_level_to_market_attractiveness * level }, text::text_color::green); + text::close_layout_box(contents, box); + } + else if(bt == economy::province_building_type::railroad) { + auto box = text::open_layout_box(contents, 0); + text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "infrastructure"), text::text_color::white); + text::add_to_layout_box(state, contents, box, std::string_view{ ":" }, text::text_color::white); + text::add_space_to_layout_box(state, contents, box); + text::add_to_layout_box(state, contents, box, text::fp_percentage{ def.infrastructure }, text::text_color::green); + text::close_layout_box(contents, box); + } + else if(bt == economy::province_building_type::fort) { + auto box = text::open_layout_box(contents, 0); + text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "FORT_LEVEL"), text::text_color::white); + text::add_to_layout_box(state, contents, box, std::string_view{ ":" }, text::text_color::white); + text::add_space_to_layout_box(state, contents, box); + text::add_to_layout_box(state, contents, box, 1, text::text_color::green); + text::close_layout_box(contents, box); + } +} + +inline void province_building_tooltip(sys::state& state, text::columnar_layout& contents, dcon::province_id p, economy::province_building_type bt) { + auto level = state.world.province_get_building_level(p, uint8_t(bt)); + + text::add_line(state, contents, state.lookup_key(economy::province_building_type_get_name(bt))); + text::add_line(state, contents, "alice_building_level", text::variable_type::val, level); + text::add_line_break_to_layout(state, contents); + + if(level > 0) { + text::add_line(state, contents, "alice_building_modifier"); + province_building_effect_tooltip(state, contents, p, bt, level); + } +}; + +inline void province_building_construction_tooltip(sys::state& state, text::columnar_layout& contents, dcon::province_id p, economy::province_building_type bt) { + text::add_line(state, contents, state.lookup_key(economy::province_building_type_get_name(bt))); + text::add_line_break_to_layout(state, contents); + + text::add_line(state, contents, "alice_new_building_modifier"); + province_building_effect_tooltip(state, contents, p, bt); + + text::add_line_break_to_layout(state, contents); + text::add_line(state, contents, "alice_building_conditions"); + int32_t current_lvl = state.world.province_get_building_level(p, uint8_t(bt)); + int32_t max_local_lvl = state.world.nation_get_max_building_level(state.local_player_nation, uint8_t(bt)); + if (bt == economy::province_building_type::fort) { + text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(p) == state.local_player_nation); + text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, p)); + + int32_t min_build = int32_t(state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::min_build_fort)); + text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); + + } else if (bt == economy::province_building_type::naval_base) { + text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(p) == state.local_player_nation); + text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, p)); + text::add_line_with_condition(state, contents, "nb_build_tt_1", state.world.province_get_is_coast(p)); + + int32_t min_build = int32_t(state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::min_build_naval_base)); + + auto si = state.world.province_get_state_membership(p); + text::add_line_with_condition(state, contents, "nb_build_tt_2", current_lvl > 0 || !si.get_naval_base_is_taken()); + + text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); + + } else { + text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(p) == state.local_player_nation); + text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, p)); + + auto rules = state.world.nation_get_combined_issue_rules(state.local_player_nation); + text::add_line_with_condition(state, contents, "rr_build_tt_1", (rules & issue_rule::build_railway) != 0); + + int32_t min_build = 0; + if (bt == economy::province_building_type::railroad) { + min_build = int32_t(state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::min_build_railroad)); + } else if (bt == economy::province_building_type::bank) { + min_build = int32_t(state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::min_build_bank)); + } else if (bt == economy::province_building_type::university) { + min_build = int32_t(state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::min_build_university)); + } + text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); + } + + text::add_line_break_to_layout(state, contents); + text::add_line(state, contents, "alice_province_building_build"); + + text::add_line_break_to_layout(state, contents); + text::add_line(state, contents, "alice_construction_cost"); + + // Construction cost goods breakdown + float factor = economy::build_cost_multiplier(state, p, false); + auto constr_cost = state.economy_definitions.building_definitions[uint8_t(bt)].cost; + + for(uint32_t i = 0; i < economy::commodity_set::set_size; ++i) { + auto box = text::open_layout_box(contents, 0); + auto cid = constr_cost.commodity_type[i]; + + if(!cid) { + break; + } + std::string padding = cid.index() < 10 ? "0" : ""; + std::string description = "@$" + padding + std::to_string(cid.index()); + text::add_unparsed_text_to_layout_box(state, contents, box, description); + text::add_to_layout_box(state, contents, box, state.world.commodity_get_name(constr_cost.commodity_type[i])); + text::add_to_layout_box(state, contents, box, std::string_view{ ": " }); + text::add_to_layout_box(state, contents, box, text::fp_one_place{ constr_cost.commodity_amounts[i] * factor }); + text::close_layout_box(contents, box); + } +}; + } // namespace ui diff --git a/src/gui/gui_effect_tooltips.cpp b/src/gui/gui_effect_tooltips.cpp index 1f03417fe..5cf885c53 100644 --- a/src/gui/gui_effect_tooltips.cpp +++ b/src/gui/gui_effect_tooltips.cpp @@ -2049,7 +2049,7 @@ uint32_t ef_tech_school(EFFECT_DISPLAY_PARAMS) { text::localised_format_box(ws, layout, box, "change_tech_school", m); text::close_layout_box(layout, box); if(ws.user_settings.spoilers) { - modifier_description(ws, layout, trigger::payload(tval[1]).mod_id, indentation + +indentation_amount); + modifier_description(ws, layout, trigger::payload(tval[1]).mod_id, indentation + +indentation_amount, 1); } return 0; } diff --git a/src/gui/gui_element_base.hpp b/src/gui/gui_element_base.hpp index c33a4e731..0e8842329 100644 --- a/src/gui/gui_element_base.hpp +++ b/src/gui/gui_element_base.hpp @@ -172,7 +172,8 @@ void multiplicative_value_modifier_description(sys::state& state, text::layout_b int32_t primary, int32_t this_slot, int32_t from_slot); void additive_value_modifier_description(sys::state& state, text::layout_base& layout, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot); -void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation = 0); + +void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation = 0, float scale = 1.f); void active_modifiers_description(sys::state& state, text::layout_base& layout, dcon::nation_id n, int32_t identation, dcon::national_modifier_value nmid, bool header); void active_modifiers_description(sys::state& state, text::layout_base& layout, dcon::province_id p, int32_t identation, diff --git a/src/gui/gui_modifier_tooltips.cpp b/src/gui/gui_modifier_tooltips.cpp index babd7514e..241d73c8d 100644 --- a/src/gui/gui_modifier_tooltips.cpp +++ b/src/gui/gui_modifier_tooltips.cpp @@ -51,7 +51,7 @@ std::string format_modifier_value(sys::state& state, float value, modifier_displ return "x%"; } -void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation) { +void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation, float scale) { auto fat_id = dcon::fatten(state.world, mid); auto const& prov_def = fat_id.get_province_values(); @@ -61,11 +61,24 @@ void modifier_description(sys::state& state, text::layout_base& layout, dcon::mo auto data = province_modifier_names[prov_def.offsets[i].index()]; auto box = text::open_layout_box(layout, indentation); text::add_to_layout_box(state, layout, box, text::produce_simple_string(state, data.name), text::text_color::white); - text::add_to_layout_box(state, layout, box, std::string_view{":"}, text::text_color::white); + text::add_to_layout_box(state, layout, box, std::string_view{ ":" }, text::text_color::white); text::add_space_to_layout_box(state, layout, box); auto color = data.positive_is_green ? (prov_def.values[i] >= 0.f ? text::text_color::green : text::text_color::red) - : (prov_def.values[i] >= 0.f ? text::text_color::red : text::text_color::green); - text::add_to_layout_box(state, layout, box, format_modifier_value(state, prov_def.values[i], data.type), color); + : (prov_def.values[i] >= 0.f ? text::text_color::red : text::text_color::green); + text::add_to_layout_box(state, layout, box, format_modifier_value(state, prov_def.values[i] * scale, data.type), color); + + // Special case since movement_cost is to show two modifiers: movement cost and trade attraction + if(prov_def.offsets[i] == sys::provincial_mod_offsets::movement_cost) { + text::close_layout_box(layout, box); + box = text::open_layout_box(layout, indentation); + + text::add_to_layout_box(state, layout, box, text::produce_simple_string(state, "alice_trade_attractiveness"), text::text_color::white); + text::add_to_layout_box(state, layout, box, std::string_view{ ":" }, text::text_color::white); + text::add_space_to_layout_box(state, layout, box); + auto color2 = (prov_def.values[i] >= 0.f ? text::text_color::red : text::text_color::green); + text::add_to_layout_box(state, layout, box, format_modifier_value(state, -1 * prov_def.values[i] * scale, data.type), color2); + } + text::close_layout_box(layout, box); } @@ -80,11 +93,10 @@ void modifier_description(sys::state& state, text::layout_base& layout, dcon::mo text::add_space_to_layout_box(state, layout, box); auto color = data.positive_is_green ? (nat_def.values[i] >= 0.f ? text::text_color::green : text::text_color::red) : (nat_def.values[i] >= 0.f ? text::text_color::red : text::text_color::green); - text::add_to_layout_box(state, layout, box, format_modifier_value(state, nat_def.values[i], data.type), color); + text::add_to_layout_box(state, layout, box, format_modifier_value(state, nat_def.values[i] * scale, data.type), color); text::close_layout_box(layout, box); } } - void active_single_modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation, bool& header, dcon::national_modifier_value nmid, float scaled) { if(scaled == 0.f) diff --git a/src/gui/gui_modifier_tooltips.hpp b/src/gui/gui_modifier_tooltips.hpp index e605557b3..8260a4093 100644 --- a/src/gui/gui_modifier_tooltips.hpp +++ b/src/gui/gui_modifier_tooltips.hpp @@ -4,7 +4,7 @@ namespace ui { -void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation); +void modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation, float scale); void active_single_modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation, bool& header, dcon::national_modifier_value nmid, float scaled = 1.f); void active_single_modifier_description(sys::state& state, text::layout_base& layout, dcon::modifier_id mid, int32_t indentation, diff --git a/src/gui/gui_province_window.hpp b/src/gui/gui_province_window.hpp index f101bfed8..9b0a4d851 100644 --- a/src/gui/gui_province_window.hpp +++ b/src/gui/gui_province_window.hpp @@ -792,6 +792,15 @@ class province_building_icon : public image_element_base { auto fat_id = dcon::fatten(state.world, prov_id); frame = fat_id.get_building_level(uint8_t(Value)); } + + tooltip_behavior has_tooltip(sys::state& state) noexcept override { + return tooltip_behavior::variable_tooltip; + } + + void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override { + auto id = retrieve(state, parent); + province_building_tooltip(state, contents, id, Value); + } }; template class province_building_expand_button : public button_element_base { @@ -834,67 +843,7 @@ class province_building_expand_button : public button_element_base { void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override { auto id = retrieve(state, parent); - - int32_t current_lvl = state.world.province_get_building_level(id, uint8_t(Value)); - int32_t max_local_lvl = state.world.nation_get_max_building_level(state.local_player_nation, uint8_t(Value)); - if constexpr(Value == economy::province_building_type::fort) { - text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(id) == state.local_player_nation); - text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, id)); - - int32_t min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_fort)); - text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); - - } else if constexpr(Value == economy::province_building_type::naval_base) { - text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(id) == state.local_player_nation); - text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, id)); - text::add_line_with_condition(state, contents, "nb_build_tt_1", state.world.province_get_is_coast(id)); - - int32_t min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_naval_base)); - - auto si = state.world.province_get_state_membership(id); - text::add_line_with_condition(state, contents, "nb_build_tt_2", current_lvl > 0 || !si.get_naval_base_is_taken()); - - text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); - - } else { - text::add_line_with_condition(state, contents, "fort_build_tt_1", state.world.province_get_nation_from_province_control(id) == state.local_player_nation); - text::add_line_with_condition(state, contents, "fort_build_tt_2", !military::province_is_under_siege(state, id)); - - auto rules = state.world.nation_get_combined_issue_rules(state.local_player_nation); - text::add_line_with_condition(state, contents, "rr_build_tt_1", (rules & issue_rule::build_railway) != 0); - - int32_t min_build = 0; - if constexpr(Value == economy::province_building_type::railroad) { - min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_railroad)); - } else if constexpr(Value == economy::province_building_type::bank) { - min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_bank)); - } else if constexpr(Value == economy::province_building_type::university) { - min_build = int32_t(state.world.province_get_modifier_values(id, sys::provincial_mod_offsets::min_build_university)); - } - text::add_line_with_condition(state, contents, "fort_build_tt_3", (max_local_lvl - current_lvl - min_build > 0), text::variable_type::x, int64_t(current_lvl), text::variable_type::n, int64_t(min_build), text::variable_type::y, int64_t(max_local_lvl)); - } - modifier_description(state, contents, state.economy_definitions.building_definitions[uint8_t(Value)].province_modifier); - text::add_line(state, contents, "alice_province_building_build"); - - // Construction cost goods breakdown - float factor = economy::build_cost_multiplier(state, id, false); - auto constr_cost = state.economy_definitions.building_definitions[uint8_t(Value)].cost; - - for(uint32_t i = 0; i < economy::commodity_set::set_size; ++i) { - auto box = text::open_layout_box(contents, 0); - auto cid = constr_cost.commodity_type[i]; - - if(!cid) { - break; - } - std::string padding = cid.index() < 10 ? "0" : ""; - std::string description = "@$" + padding + std::to_string(cid.index()); - text::add_unparsed_text_to_layout_box(state, contents, box, description); - text::add_to_layout_box(state, contents, box, state.world.commodity_get_name(constr_cost.commodity_type[i])); - text::add_to_layout_box(state, contents, box, std::string_view{ ": " }); - text::add_to_layout_box(state, contents, box, text::fp_one_place{ constr_cost.commodity_amounts[i] * factor }); - text::close_layout_box(contents, box); - } + province_building_construction_tooltip(state, contents, id, Value); } }; diff --git a/src/gui/province_tiles/gui_province_tiles_tiles.hpp b/src/gui/province_tiles/gui_province_tiles_tiles.hpp index bf85ef337..e67ddf14b 100644 --- a/src/gui/province_tiles/gui_province_tiles_tiles.hpp +++ b/src/gui/province_tiles/gui_province_tiles_tiles.hpp @@ -2,6 +2,8 @@ #include "gui_element_types.hpp" #include "gui_context_window.hpp" +#include "gui_province_window.hpp" +#include "economy_trade_routes.hpp" #include "military.hpp" #include "ai.hpp" @@ -203,7 +205,11 @@ class province_building_tile : public tile_type_logic { } int get_frame(sys::state& state, province_tile target) noexcept override { - if(target.province_building == economy::province_building_type::railroad) { + auto level = state.world.province_get_building_level(target.province, uint8_t(target.province_building)); + + if(target.province_building == economy::province_building_type::railroad && level == 0) { + return 21; + } else if(target.province_building == economy::province_building_type::railroad && level > 0) { return 8; } else if(target.province_building == economy::province_building_type::naval_base) { return 9; @@ -215,9 +221,8 @@ class province_building_tile : public tile_type_logic { void button_action(sys::state& state, province_tile target, ui::element_base* parent) noexcept override { } - // Done void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { - text::add_line(state, contents, state.lookup_key(economy::province_building_type_get_name(target.province_building))); + province_building_tooltip(state, contents, target.province, target.province_building); } }; @@ -244,7 +249,7 @@ class province_resource_potential_tile : public tile_type_logic { } void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { - auto limit = state.world.province_get_factory_max_size(target.province, target.potential_commodity); + auto limit = state.world.province_get_factory_max_size(target.province, target.potential_commodity) / 10000.f; text::add_line(state, contents, "available_potential", text::variable_type::what, state.world.commodity_get_name(target.potential_commodity), text::variable_type::val, (int)limit); } @@ -302,4 +307,190 @@ class factory_construction_tile : public tile_type_logic { } }; + +class local_administration_tile : public tile_type_logic { +public: + dcon::text_key get_name(sys::state& state, province_tile target) noexcept override { + return state.lookup_key("administration_tile"); + } + + bool is_available(sys::state& state, province_tile target) noexcept override { + return true; + } + + int get_frame(sys::state& state, province_tile target) noexcept override { + return 15; + } + + void button_action(sys::state& state, province_tile target, ui::element_base* parent) noexcept override { } + + void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { + auto n = state.world.province_get_nation_from_province_ownership(target.province); + auto budget_priority = float(state.world.nation_get_administrative_spending(state.local_player_nation)) / 100.f; + + text::add_line(state, contents, "local_admin"); + + text::add_line(state, contents, "local_admin_spending", text::variable_type::value, text::fp_currency{ economy::estimate_spendings_administration(state, n, budget_priority) }); + + auto employment = economy::explain_capital_administration_employment(state, n); + auto target_employment = state.world.nation_get_administration_employment_target_in_capital(n); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(target.province, economy::labor::high_education_and_accepted); + auto wage = state.world.province_get_labor_price(target.province, economy::labor::high_education_and_accepted); + text::add_line(state, contents, "local_admin_employment", text::variable_type::value, text::fp_one_place{ employment }); + text::add_line(state, contents, "employment_type_high_education_and_accepted", 15); + text::add_line(state, contents, "target_employment", text::variable_type::value, text::fp_one_place{ target_employment }, 15); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 15); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 15); + + text::add_line(state, contents, "local_admin_efficiency", text::variable_type::value, text::fp_percentage{ economy::local_administration_efficiency }); + + text::add_line_break_to_layout(state, contents); + + auto info = economy::explain_tax_income_local(state, n, target.province); + + text::add_line(state, contents, "tax_collection_rate", text::variable_type::value, text::fp_percentage{ info.local_multiplier }); + text::add_line(state, contents, "poor_potential", text::variable_type::value, text::fp_currency{ info.poor_potential }); + text::add_line(state, contents, "mid_potential", text::variable_type::value, text::fp_percentage{ info.mid_potential }); + text::add_line(state, contents, "rich_potential", text::variable_type::value, text::fp_percentage{ info.rich_potential }); + text::add_line(state, contents, "poor_taxes", text::variable_type::value, text::fp_percentage{ info.poor }); + text::add_line(state, contents, "mid_taxes", text::variable_type::value, text::fp_percentage{ info.mid }); + text::add_line(state, contents, "rich_taxes", text::variable_type::value, text::fp_percentage{ info.rich }); + } +}; + + +class capital_administration_tile : public tile_type_logic { +public: + dcon::text_key get_name(sys::state& state, province_tile target) noexcept override { + return state.lookup_key("administration_tile"); + } + + bool is_available(sys::state& state, province_tile target) noexcept override { + return true; + } + + int get_frame(sys::state& state, province_tile target) noexcept override { + return 17; + } + + void button_action(sys::state& state, province_tile target, ui::element_base* parent) noexcept override { } + + void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { + auto n = state.world.province_get_nation_from_province_ownership(target.province); + auto budget_priority = float(state.world.nation_get_administrative_spending(state.local_player_nation)) / 100.f; + + text::add_line(state, contents, "capital_admin"); + + text::add_line(state, contents, "local_admin_spending", text::variable_type::value, text::fp_currency{ economy::estimate_spendings_administration_capital(state, n, budget_priority) }); + + text::add_line_break_to_layout(state, contents); + + auto employment = economy::explain_capital_administration_employment(state, n); + auto target_employment = state.world.nation_get_administration_employment_target_in_capital(n); + auto satisfaction = state.world.province_get_labor_demand_satisfaction(target.province, economy::labor::high_education_and_accepted); + text::add_line(state, contents, "local_admin_employment", text::variable_type::value, text::fp_one_place{ employment }); + text::add_line(state, contents, "employment_type_high_education_and_accepted", 15); + text::add_line(state, contents, "target_employment", text::variable_type::value, text::fp_one_place{ target_employment }, 15); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 15); + + auto wage = state.world.province_get_labor_price(target.province, economy::labor::high_education_and_accepted); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 15); + + text::add_line_break_to_layout(state, contents); + + auto info = economy::explain_tax_income_local(state, n, target.province); + + text::add_line(state, contents, "tax_collection_rate", text::variable_type::value, text::fp_percentage{ info.local_multiplier }); + text::add_line_break_to_layout(state, contents); + + + text::add_line(state, contents, "poor_taxes", text::variable_type::value, text::fp_currency{ info.poor }); + text::add_line(state, contents, "poor_potential", text::variable_type::value, text::fp_currency{ info.poor_potential }, 15); + text::add_line(state, contents, "mid_taxes", text::variable_type::value, text::fp_currency{ info.mid }); + text::add_line(state, contents, "mid_potential", text::variable_type::value, text::fp_currency{ info.mid_potential }, 15); + text::add_line(state, contents, "rich_taxes", text::variable_type::value, text::fp_currency{ info.rich }); + text::add_line(state, contents, "rich_potential", text::variable_type::value, text::fp_currency{ info.rich_potential }, 15); + } +}; + +class no_administration_tile : public tile_type_logic { +public: + dcon::text_key get_name(sys::state& state, province_tile target) noexcept override { + return state.lookup_key("administration_tile"); + } + + bool is_available(sys::state& state, province_tile target) noexcept override { + return true; + } + + int get_frame(sys::state& state, province_tile target) noexcept override { + return 18; + } + + void button_action(sys::state& state, province_tile target, ui::element_base* parent) noexcept override { } + + void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { + auto n = state.world.province_get_nation_from_province_ownership(target.province); + + auto info = economy::explain_tax_income_local(state, n, target.province); + + text::add_line(state, contents, "tax_collection_rate", text::variable_type::value, text::fp_percentage{ info.local_multiplier }); + text::add_line_break_to_layout(state, contents); + + + text::add_line(state, contents, "poor_taxes", text::variable_type::value, text::fp_currency{ info.poor }); + text::add_line(state, contents, "poor_potential", text::variable_type::value, text::fp_currency{ info.poor_potential }, 15); + text::add_line(state, contents, "mid_taxes", text::variable_type::value, text::fp_currency{ info.mid }); + text::add_line(state, contents, "mid_potential", text::variable_type::value, text::fp_currency{ info.mid_potential }, 15); + text::add_line(state, contents, "rich_taxes", text::variable_type::value, text::fp_currency{ info.rich }); + text::add_line(state, contents, "rich_potential", text::variable_type::value, text::fp_currency{ info.rich_potential }, 15); + } +}; + +class market_tile : public tile_type_logic { +public: + dcon::text_key get_name(sys::state& state, province_tile target) noexcept override { + return state.lookup_key("market_tile"); + } + + bool is_available(sys::state& state, province_tile target) noexcept override { + return true; + } + + int get_frame(sys::state& state, province_tile target) noexcept override { + return 16; + } + + void button_action(sys::state& state, province_tile target, ui::element_base* parent) noexcept override { + // send(state, parent, province_subtab_toggle_signal::economy); + } + + void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents, province_tile target) noexcept override { + auto n = state.world.province_get_nation_from_province_ownership(target.province); + + text::add_line(state, contents, "trade_center"); + text::add_line(state, contents, "trade_center_desc"); + + text::add_line_break_to_layout(state, contents); + economy::make_trade_center_tooltip(state, contents, target.market); + text::add_line_break_to_layout(state, contents); + + auto external_trade_employment = economy::transportation_between_markets_labor_demand(state, target.market); + // Since the tile is rendered only for state capitals, we assume that target.province = market capital + auto internal_trade_employment = economy::transportation_inside_market_labor_demand(state, target.market, target.province); + auto target_employment = external_trade_employment + internal_trade_employment; + + auto satisfaction = state.world.province_get_labor_demand_satisfaction(target.province, economy::labor::no_education); + auto employment = target_employment * satisfaction; + text::add_line(state, contents, "trade_center_employment", text::variable_type::value, text::fp_one_place{ employment }); + text::add_line(state, contents, "employment_type_no_education", 15); + text::add_line(state, contents, "target_employment", text::variable_type::value, text::fp_one_place{ target_employment }, 15); + text::add_line(state, contents, "employment_satisfaction", text::variable_type::value, text::fp_percentage{ satisfaction }, 15); + + auto wage = (state.world.province_get_labor_price(target.province, economy::labor::no_education) + 0.00001f); + text::add_line(state, contents, "wage", text::variable_type::value, text::fp_one_place{ wage }, 15); + + } +}; + } // namespace ui diff --git a/src/gui/province_tiles/gui_province_tiles_window.hpp b/src/gui/province_tiles/gui_province_tiles_window.hpp index c239bac24..0347e2d52 100644 --- a/src/gui/province_tiles/gui_province_tiles_window.hpp +++ b/src/gui/province_tiles/gui_province_tiles_window.hpp @@ -15,7 +15,10 @@ inline static province_building_tile province_building_tile_logic; inline static province_resource_potential_tile province_resource_potential_tile_logic; inline static province_build_new_tile province_build_new_tile_logic; inline static factory_construction_tile factory_construction_tile_logic; - +inline static local_administration_tile local_administration_tile_logic; +inline static capital_administration_tile capital_administration_tile_logic; +inline static no_administration_tile no_administration_tile_logic; +inline static market_tile market_tile_logic; class province_tile_button : public button_element_base { public: @@ -31,6 +34,17 @@ class province_tile_button : public button_element_base { if(tile.empty) { tile_logic = &empty_tile_logic; } + else if(tile.capital_administration) { + tile_logic = &capital_administration_tile_logic; + } + else if(tile.local_administration) { + tile_logic = &local_administration_tile_logic; + } else if(tile.no_administration_tile) { + tile_logic = &no_administration_tile_logic; + } + else if(tile.market) { + tile_logic = &market_tile_logic; + } else if(tile.rgo_commodity) { tile_logic = &rgo_tile_logic; } diff --git a/src/gui/province_tiles/province_tiles.cpp b/src/gui/province_tiles/province_tiles.cpp index 3cc91d430..1f389a2d9 100644 --- a/src/gui/province_tiles/province_tiles.cpp +++ b/src/gui/province_tiles/province_tiles.cpp @@ -10,9 +10,54 @@ std::vector retrieve_province_tiles(sys::state& state, dcon::prov std::vector tiles = std::vector(64); auto owner = state.world.province_get_nation_from_province_ownership(p); + auto si = state.world.province_get_state_membership(p); int curind = 0; + if(owner) { + bool administration_found = false; + + // Capital administration is located in the nation capital + if(state.world.nation_get_capital(owner) == p) { + tiles[curind].capital_administration = true; + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + + administration_found = true; + } + + for(auto admin : state.world.nation_get_nation_administration(owner)) { + if(admin.get_administration().get_capital() == p) { + // There can be several administrations per state located in any province of the state + tiles[curind].local_administration = admin.get_administration(); + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + + administration_found = true; + break; + } + } + + // If there is no administration in the province, we display a tile with a small tax office. + if(!administration_found) { + tiles[curind].no_administration_tile = true; + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + } + + // Market is located in the capital of the state instabce + if(state.world.state_instance_get_capital(si) == p) { + auto market = state.world.state_instance_get_market_from_local_market(si); + tiles[curind].market = market; + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + } + } + // Main province RGOs tiles[curind].rgo_commodity = state.world.province_get_rgo(p); tiles[curind].empty = false; @@ -32,13 +77,58 @@ std::vector retrieve_province_tiles(sys::state& state, dcon::prov } } - for(auto f : state.world.in_factory) { - if(f.get_factory_location().get_province() == p) { - tiles[curind].factory = f; + if(owner) { + for(auto f : state.world.in_factory) { + if(f.get_factory_location().get_province() == p) { + tiles[curind].factory = f; + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + } + } + + for(auto r : state.world.in_regiment_source) { + if(r.get_pop().get_province_from_pop_location() == p) { + tiles[curind].regiment = r.get_regiment(); + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + } + } + + if (state.world.province_get_building_level(p, uint8_t(economy::province_building_type::naval_base)) > 0) { + tiles[curind].province_building = economy::province_building_type::naval_base; + tiles[curind].empty = false; + tiles[curind].has_province_building = true; + tiles[curind].province = p; + curind++; + } + + // if(state.world.province_get_building_level(p, uint8_t(economy::province_building_type::railroad) > 0) { + { + tiles[curind].province_building = economy::province_building_type::railroad; + tiles[curind].empty = false; + tiles[curind].has_province_building = true; + tiles[curind].province = p; + curind++; + } + + if(state.world.province_get_building_level(p, uint8_t(economy::province_building_type::fort)) > 0) { + tiles[curind].province_building = economy::province_building_type::fort; tiles[curind].empty = false; + tiles[curind].has_province_building = true; tiles[curind].province = p; curind++; } + + for(auto fc : state.world.in_factory_construction) { + if(fc.get_province() == p) { + tiles[curind].factory_construction = fc; + tiles[curind].empty = false; + tiles[curind].province = p; + curind++; + } + } } for(auto c : state.world.in_commodity) { @@ -66,48 +156,6 @@ std::vector retrieve_province_tiles(sys::state& state, dcon::prov } } - for(auto r : state.world.in_regiment_source) { - if(r.get_pop().get_province_from_pop_location() == p) { - tiles[curind].regiment = r.get_regiment(); - tiles[curind].empty = false; - tiles[curind].province = p; - curind++; - } - } - - for(int i = 0; i < state.world.province_get_building_level(p, uint8_t(economy::province_building_type::naval_base)); i++) { - tiles[curind].province_building = economy::province_building_type::naval_base; - tiles[curind].empty = false; - tiles[curind].has_province_building = true; - tiles[curind].province = p; - curind++; - } - - for(int i = 0; i < state.world.province_get_building_level(p, uint8_t(economy::province_building_type::railroad)); i++) { - tiles[curind].province_building = economy::province_building_type::railroad; - tiles[curind].empty = false; - tiles[curind].has_province_building = true; - tiles[curind].province = p; - curind++; - } - - for(int i = 0; i < state.world.province_get_building_level(p, uint8_t(economy::province_building_type::fort)); i++) { - tiles[curind].province_building = economy::province_building_type::fort; - tiles[curind].empty = false; - tiles[curind].has_province_building = true; - tiles[curind].province = p; - curind++; - } - - for(auto fc : state.world.in_factory_construction) { - if(fc.get_province() == p) { - tiles[curind].factory_construction = fc; - tiles[curind].empty = false; - tiles[curind].province = p; - curind++; - } - } - /* * Since from province UI we can build factories, buildings, regiments, and ships. I don't think it'd be useful to duplicate them with "new" submenu. if(curind < 64) { diff --git a/src/gui/province_tiles/province_tiles.hpp b/src/gui/province_tiles/province_tiles.hpp index 380ce1176..eaa8d9a9a 100644 --- a/src/gui/province_tiles/province_tiles.hpp +++ b/src/gui/province_tiles/province_tiles.hpp @@ -10,6 +10,10 @@ struct province_tile { bool empty = true; bool build_new = false; dcon::province_id province; + dcon::administration_id local_administration; + bool capital_administration = false; + bool no_administration_tile = false; + dcon::market_id market; dcon::commodity_id rgo_commodity; dcon::commodity_id potential_commodity; dcon::factory_id factory; diff --git a/src/gui/topbar_subwindows/production_subwindows/gui_build_factory_window.hpp b/src/gui/topbar_subwindows/production_subwindows/gui_build_factory_window.hpp index 58dbd28b8..2c2cf04b9 100644 --- a/src/gui/topbar_subwindows/production_subwindows/gui_build_factory_window.hpp +++ b/src/gui/topbar_subwindows/production_subwindows/gui_build_factory_window.hpp @@ -212,7 +212,7 @@ class factory_build_item_button : public tinted_button_element_base { text::add_line_break_to_layout(state, contents); // List factory type construction costs - text::add_line(state, contents, "alice_factory_construction_cost"); + text::add_line(state, contents, "alice_construction_cost"); auto const& cset = state.world.factory_type_get_construction_costs(content); for(uint32_t i = 0; i < economy::commodity_set::set_size; i++) { if(cset.commodity_type[i] && cset.commodity_amounts[i] > 0.0f) { diff --git a/src/nations/nations.cpp b/src/nations/nations.cpp index 935ccfc4d..416350e7f 100644 --- a/src/nations/nations.cpp +++ b/src/nations/nations.cpp @@ -445,9 +445,8 @@ void generate_sea_trade_routes(sys::state& state) { auto continent_origin = state.world.province_get_continent(state_owner_capital); float mult = 1.f; - mult += std::min(naval_base_origin, naval_base_target) * 0.25f; + mult += std::min(naval_base_origin, naval_base_target) * naval_base_level_to_market_attractiveness; bool must_connect = same_owner && different_region && capital_and_connected_region; - auto distance_approximation = province::direct_distance(state, coast_0, coast_1) / base_speed; diff --git a/src/nations/nations.hpp b/src/nations/nations.hpp index a82c16c84..71462c9df 100644 --- a/src/nations/nations.hpp +++ b/src/nations/nations.hpp @@ -8,6 +8,9 @@ enum class crisis_state : uint32_t; } namespace nations { + +inline float naval_base_level_to_market_attractiveness = 0.25f; + inline uint32_t tag_to_int(char first, char second, char third) { return (uint32_t(first) << 16) | (uint32_t(second) << 8) | (uint32_t(third) << 0); }