diff --git a/assets/alice.gui b/assets/alice.gui index 14c44a086..d0a91a3b4 100644 --- a/assets/alice.gui +++ b/assets/alice.gui @@ -3894,6 +3894,83 @@ guiTypes = { format = left } } + + iconType = { + name ="gdp_ledger_linegraph_bg" + spriteType = "GFX_ledger_linegraph_bg" + position = { x= 63 y = 151 } + Orientation = "UPPER_LEFT" + } + + windowType = { + name = "gdp_ledger_linegraphs" + backGround ="" + position = { x = 80 y = 130 } + size = { x=690 y = 540 } + moveable = 0 + dontRender = "" + horizontalBorder = "0" + verticalBorder = "" + fullScreen = no + } + + windowType = { + name = "gdp_ledger_linegraph_legend" + backGround ="" + position = { x = 830 y = 153 } + size = { x=200 y = 540 } + moveable = 0 + dontRender = "" + horizontalBorder = "0" + verticalBorder = "" + fullScreen = no + + listboxType = { + name ="legend_nations_list" + position = { x = 0 y = 0 } + backGround="" + size = { x=208 y = 528 } + Orientation = "UPPER_LEFT" + spacing = 2 + scrollbartype = "standardlistbox_slider" + borderSize = {x = 1 y = 1} + } + } + + windowType = { + name = "ledger_nations_legend_entry" + backGround="" + position = { x=0 y=-0 } + size = { x=200 y=24 } + moveable = 0 + dontRender = "" + horizontalBorder= "" + verticalBorder= "" + fullScreen = no + Orientation = "UPPER_LEFT" + + checkboxType = { + name = "nation_ledger_legend_checkbox" + position = {x = 24 y = 1 } + quadTextureSprite ="GFX_checkbox_default" + } + + iconType = { + name ="nation_ledger_legend_plupp" + spriteType = "GFX_politics_party_plupp" + position = { x= 0 y = 0 } + } + + instantTextBoxType = { + name = "nation_ledger_default_textbox" + position = { x = 47 y = 5 } + font = "Arial12_bold_black" + text = " " + maxWidth = 160 + maxHeight = 16 + fixedsize = yes + } + } checkboxType = { name = "alice_debt_checkbox" diff --git a/assets/localisation/ar-AR/alice.csv b/assets/localisation/ar-AR/alice.csv index 2257bd479..ee14bc11c 100644 --- a/assets/localisation/ar-AR/alice.csv +++ b/assets/localisation/ar-AR/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;محدد المقاطعة modifier_province_immigrator;مهاجر المحافظة modifier_conversion_rate;معدل التحويل modifier_attrition;الاستنزاف -chat_player_joins;انضم @$x$ $playername$ -chat_player_leaves;@$x$ $playername$ متبقي -chat_player_ban;تم حظر @$x$ $playername$ -chat_player_kick;تم طرد @$x$ $playername$ -chat_player_switch;@$x$ $playername$ اختار $country$ -chat_player_oos;تم تسجيل @$x$ $playername$! +chat_player_joins;انضم $playername$ +chat_player_leaves;$playername$ متبقي +chat_player_ban;تم حظر $playername$ +chat_player_kick;تم طرد $playername$ +chat_player_switch;$playername$ اختار $country$ +chat_player_oos;تم تسجيل $playername$! alice_status_stream;حفظ التقدم $value$ alice_play_pending_client;$playername$ ليس جاهزًا بعد alice_stockpile_button_0_0;"تعمل المخزونات الوطنية بمثابة بهار للأنشطة الاقتصادية والتجارية المعتادة، حيث يرى الناس خطوط ""Ggreen""W ترتفع، و""Rred""W خطوط تنخفض، كما هو معتاد أنا ""Ynot؟""W رسم بياني خطي لذلك أنا في الغالب تمر مرور الكرام :)" diff --git a/assets/localisation/de-DE/alice.csv b/assets/localisation/de-DE/alice.csv index aa8e3ce80..3c29d45aa 100644 --- a/assets/localisation/de-DE/alice.csv +++ b/assets/localisation/de-DE/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Provinzauswahl modifier_province_immigrator;Einwanderer aus der Provinz modifier_conversion_rate;Wechselkurs modifier_attrition;Attrition -chat_player_joins;@$x$ $playername$ ist beigetreten -chat_player_leaves;@$x$ $playername$ übrig -chat_player_ban;@$x$ $playername$ wurde gesperrt -chat_player_kick;@$x$ $playername$ wurde gekickt -chat_player_switch;@$x$ $playername$ hat $country$ ausgewählt -chat_player_oos;@$x$ $playername$ hat OOSed! +chat_player_joins;$playername$ ist beigetreten +chat_player_leaves;$playername$ übrig +chat_player_ban;$playername$ wurde gesperrt +chat_player_kick;$playername$ wurde gekickt +chat_player_switch;$playername$ hat $country$ ausgewählt +chat_player_oos;$playername$ hat OOSed! alice_status_stream;Speichern Sie den Fortschritt $value$ alice_play_pending_client;$playername$ ist noch nicht fertig alice_stockpile_button_0_0;Nationale Vorräte fungieren als Gewürz für Ihre üblichen Wirtschafts- und Geschäftsaktivitäten, bei denen die Leute sehen, dass die „Ggrünen“ W-Linien nach oben und die „RRoten“ W-Linien nach unten gehen. Wie üblich bin ich kein Liniendiagramm, also meistens unbemerkt bleiben :) diff --git a/assets/localisation/en-US/alice.csv b/assets/localisation/en-US/alice.csv index d1cd29897..b05a66515 100644 --- a/assets/localisation/en-US/alice.csv +++ b/assets/localisation/en-US/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Province selector modifier_province_immigrator;Province immigrator modifier_conversion_rate;Conversion Rate modifier_attrition;Attrition -chat_player_joins;@$x$ $playername$ joined -chat_player_leaves;@$x$ $playername$ left -chat_player_ban;@$x$ $playername$ was banned -chat_player_kick;@$x$ $playername$ was kicked -chat_player_switch;@$x$ $playername$ has choosen $country$ -chat_player_oos;@$x$ $playername$ has OOSed! +chat_player_joins;$playername$ joined +chat_player_leaves;$playername$ left +chat_player_ban;$playername$ was banned +chat_player_kick;$playername$ was kicked +chat_player_switch;$playername$ has choosen $country$ +chat_player_oos;$playername$ has OOSed! alice_status_stream;Save progress $value$ alice_play_pending_client;$playername$ is not ready yet alice_stockpile_button_0_0;National stockpiles function as a condiment to your usual economic-business activities, where people see ?Ggreen?W lines go up, and ?Rred?W lines go down, as per usual I'm ?Ynot?W a line graph so I mostly go unnoticed :) @@ -1194,3 +1194,4 @@ alice_pnt_dominant_religion;?YDominant religion:?! $x$ alice_pnt_dominant_ideology;?YDominant Ideology:?! $x$ ledger_ppp_gdp;GDP(PPP) ledger_ppp_gdp_per_capita;GDP(PPP) per 1m people +alice_ledger_header_gdp_history;GDP(PPP) over time diff --git a/assets/localisation/es-ES/alice.csv b/assets/localisation/es-ES/alice.csv index 89a99603f..627db780c 100644 --- a/assets/localisation/es-ES/alice.csv +++ b/assets/localisation/es-ES/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Selector provincial modifier_province_immigrator;Inmigrador provincial modifier_conversion_rate; modifier_attrition; -chat_player_joins;@$x$ $playername$ se unio -chat_player_leaves;@$x$ $playername$ se fue -chat_player_ban;@$x$ $playername$ fue baneado -chat_player_kick;@$x$ $playername$ fue vetado -chat_player_switch;@$x$ $playername$ ahora es $country$ -chat_player_oos; +chat_player_joins;$playername$ se unio +chat_player_leaves;$playername$ se fue +chat_player_ban;$playername$ fue baneado +chat_player_kick;$playername$ fue vetado +chat_player_switch;$playername$ ahora es $country$ +chat_player_oos;$playername$ se ha OOSeado alice_status_stream;Progreso $value$ alice_play_pending_client;$playername$ no esta listo/a todavia alice_stockpile_button_0_0; diff --git a/assets/localisation/hu-HU/alice.csv b/assets/localisation/hu-HU/alice.csv index f093a6ef5..edc50de94 100644 --- a/assets/localisation/hu-HU/alice.csv +++ b/assets/localisation/hu-HU/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Tartományválasztó modifier_province_immigrator;Tartományi bevándorló modifier_conversion_rate;Konverziós arány modifier_attrition;Kopás -chat_player_joins;@$x$ $playername$ csatlakozott -chat_player_leaves;@$x$ $playername$ maradt -chat_player_ban;@$x$ $playername$ kitiltva lett -chat_player_kick;@$x$ $playername$ rúgott -chat_player_switch;@$x$ $playername$ a $country$ lehetőséget választotta -chat_player_oos;@$x$ $playername$ OOS-t kapott! +chat_player_joins;$playername$ csatlakozott +chat_player_leaves;$playername$ maradt +chat_player_ban;$playername$ kitiltva lett +chat_player_kick;$playername$ rúgott +chat_player_switch;$playername$ a $country$ lehetőséget választotta +chat_player_oos;$playername$ OOS-t kapott! alice_status_stream;A folyamat mentése $érték$ alice_play_pending_client;$playername$ még nincs kész alice_stockpile_button_0_0;"A nemzeti készletek az Ön szokásos gazdasági-üzleti tevékenységeinek fűszereként funkcionálnak, ahol az emberek azt látják, hogy a ""Ggreen"" W vonalak felfelé, a ""Rred"" W vonalak pedig lefelé haladnak, a szokásos módon én nem vagyok vonaldiagram, így többnyire észrevétlen marad :)" diff --git a/assets/localisation/it-IT/alice.csv b/assets/localisation/it-IT/alice.csv index 02807da5b..e85d0f53e 100644 --- a/assets/localisation/it-IT/alice.csv +++ b/assets/localisation/it-IT/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Selettore della provincia modifier_province_immigrator;Immigrato della provincia modifier_conversion_rate;Tasso di conversione modifier_attrition;Attrito -chat_player_joins;@$x$ $playername$ si è iscritto -chat_player_leaves;@$x$ $playername$ rimasto -chat_player_ban;@$x$ $playername$ è stato bannato -chat_player_kick;@$x$ $playername$ è stato espulso -chat_player_switch;@$x$ $playername$ ha scelto $country$ -chat_player_oos;@$x$ $playername$ è fuori servizio! +chat_player_joins;$playername$ si è iscritto +chat_player_leaves;$playername$ rimasto +chat_player_ban;$playername$ è stato bannato +chat_player_kick;$playername$ è stato espulso +chat_player_switch;$playername$ ha scelto $country$ +chat_player_oos;$playername$ è fuori servizio! alice_status_stream;Salva i progressi $value$ alice_play_pending_client;$playername$ non è ancora pronto alice_stockpile_button_0_0;Le scorte nazionali funzionano come un condimento per le vostre consuete attività economico-commerciali, in cui le persone vedono le linee ?Ggreen?W salire e le linee ?Rred?W scendere, come al solito sono ?Ynot?W un grafico a linee, quindi per lo più Andare inosservato :) diff --git a/assets/localisation/ko-SK/alice.csv b/assets/localisation/ko-SK/alice.csv index 7586a36ed..051543c4c 100644 --- a/assets/localisation/ko-SK/alice.csv +++ b/assets/localisation/ko-SK/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;지방 선택기 modifier_province_immigrator;지방 이민자 modifier_conversion_rate;전환율 modifier_attrition;마찰 -chat_player_joins;@$x$ $playername$님이 합류했습니다 -chat_player_leaves;@$x$ $playername$ 남음 -chat_player_ban;@$x$ $playername$이(가) 차단되었습니다 -chat_player_kick;@$x$ $playername$이(가) 추방되었습니다 -chat_player_switch;@$x$ $playername$님이 $country$을 선택했습니다. -chat_player_oos;@$x$ $playername$이 OOS를 받았습니다! +chat_player_joins;$playername$님이 합류했습니다 +chat_player_leaves;$playername$ 남음 +chat_player_ban;$playername$이(가) 차단되었습니다 +chat_player_kick;$playername$이(가) 추방되었습니다 +chat_player_switch;$playername$님이 $country$을 선택했습니다. +chat_player_oos;$playername$이 OOS를 받았습니다! alice_status_stream;진행 상황 $value$ 저장 alice_play_pending_client;$playername$은(는) 아직 준비되지 않았습니다. alice_stockpile_button_0_0;국가 비축량은 일반적인 경제-비즈니스 활동에 대한 조미료 역할을 합니다. 사람들은 ?Ggreen?W 선이 올라가고 ?Rred?W 선이 내려가는 것을 봅니다. 평소와 같이 나는 ?Ynot?W 선 그래프이므로 대부분 눈에 띄지 않게 가세요 :) diff --git a/assets/localisation/nl-NL/alice.csv b/assets/localisation/nl-NL/alice.csv index ab2b6ad77..74a9b87a7 100644 --- a/assets/localisation/nl-NL/alice.csv +++ b/assets/localisation/nl-NL/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Provinciekiezer modifier_province_immigrator;Immigrant uit de provincie modifier_conversion_rate;Conversiepercentage modifier_attrition;Slijtage -chat_player_joins;@$x$ $spelernaam$ is lid geworden -chat_player_leaves;@$x$ $spelernaam$ over -chat_player_ban;@$x$ $spelernaam$ is verbannen -chat_player_kick;@$x$ $spelernaam$ is geschopt -chat_player_switch;@$x$ $playername$ heeft $country$ gekozen -chat_player_oos;@$x$ $playername$ heeft OOSed! +chat_player_joins;$spelernaam$ is lid geworden +chat_player_leaves;$spelernaam$ over +chat_player_ban;$spelernaam$ is verbannen +chat_player_kick;$spelernaam$ is geschopt +chat_player_switch;$playername$ heeft $country$ gekozen +chat_player_oos;$playername$ heeft OOSed! alice_status_stream;Bewaar voortgang $value$ alice_play_pending_client;$playername$ is nog niet klaar alice_stockpile_button_0_0;Nationale voorraden fungeren als aanvulling op uw gebruikelijke economisch-zakelijke activiteiten, waar mensen 'Ggroene' W-lijnen omhoog zien gaan en 'Rred' W-lijnen omlaag gaan, zoals gewoonlijk ben ik 'Ynot'W een lijngrafiek, dus ik ben meestal onopgemerkt gaan :) diff --git a/assets/localisation/pl-PL/alice.csv b/assets/localisation/pl-PL/alice.csv index 90b8ebc32..171d2c295 100644 --- a/assets/localisation/pl-PL/alice.csv +++ b/assets/localisation/pl-PL/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;Selektor prowincji modifier_province_immigrator;Imigrant z prowincji modifier_conversion_rate;Współczynnik konwersji modifier_attrition;Ścieranie -chat_player_joins;Dołączył @$x$ $nazwa_gracza$ -chat_player_leaves;Pozostało @$x$ $nazwa_gracza$ -chat_player_ban;@$x$ $playername$ został zbanowany -chat_player_kick;@$x$ $playername$ został wyrzucony -chat_player_switch;@$x$ $playername$ wybrał $country$ -chat_player_oos;@$x$ $playername$ przeszedł OOS! +chat_player_joins;Dołączył $nazwa_gracza$ +chat_player_leaves;Pozostało $nazwa_gracza$ +chat_player_ban;$playername$ został zbanowany +chat_player_kick;$playername$ został wyrzucony +chat_player_switch;$playername$ wybrał $country$ +chat_player_oos;$playername$ przeszedł OOS! alice_status_stream;Zapisz postęp $wartość$ alice_play_pending_client;$playername$ nie jest jeszcze gotowy alice_stockpile_button_0_0;Krajowe zapasy stanowią dodatek do zwykłej działalności gospodarczo-biznesowej, gdzie ludzie widzą, jak linie „Ggreen” W rosną, a linie „Rred” W maleją, jak zwykle „Jestem” „Ynot” to wykres liniowy, więc głównie pozostać niezauważonym :) diff --git a/assets/localisation/ru-RU/alice.csv b/assets/localisation/ru-RU/alice.csv index 8e07419ef..a1e6dfa6a 100644 --- a/assets/localisation/ru-RU/alice.csv +++ b/assets/localisation/ru-RU/alice.csv @@ -907,12 +907,12 @@ modifier_province_selector;Province selector modifier_province_immigrator;Province immigrator modifier_conversion_rate;Conversion Rate modifier_attrition;Attrition -chat_player_joins;@$x$ $playername$ joined -chat_player_leaves;@$x$ $playername$ left -chat_player_ban;@$x$ $playername$ was banned -chat_player_kick;@$x$ $playername$ was kicked -chat_player_switch;@$x$ $playername$ has choosen $country$ -chat_player_oos;@$x$ $playername$ has OOSed! +chat_player_joins;$playername$ joined +chat_player_leaves;$playername$ left +chat_player_ban;$playername$ was banned +chat_player_kick;$playername$ was kicked +chat_player_switch;$playername$ has choosen $country$ +chat_player_oos;$playername$ has OOSed! alice_status_stream;Save progress $value$ alice_play_pending_client;$playername$ is not ready yet alice_stockpile_button_0_0;National stockpiles function as a condiment to your usual economic-business activities, where people see ?Ggreen?W lines go up, and ?Rred?W lines go down, as per usual I'm ?Ynot?W a line graph so I mostly go unnoticed :) diff --git a/assets/localisation/zh-CN/alice.csv b/assets/localisation/zh-CN/alice.csv index c3f68cfad..773aa9d8e 100644 --- a/assets/localisation/zh-CN/alice.csv +++ b/assets/localisation/zh-CN/alice.csv @@ -909,12 +909,12 @@ modifier_province_selector;省选区 modifier_province_immigrator;省移民 modifier_conversion_rate;传教率 modifier_attrition;损耗 -chat_player_joins;@$x$$playername$加入 -chat_player_leaves;@$x$$playername$离开 -chat_player_ban;@$x$$playername$被封禁 -chat_player_kick;@$x$$playername$被踢除 -chat_player_switch;@$x$$playername$选择了$country$ -chat_player_oos;@$x$$playername$已断开连接! +chat_player_joins;$playername$加入 +chat_player_leaves;$playername$离开 +chat_player_ban;$playername$被封禁 +chat_player_kick;$playername$被踢除 +chat_player_switch;$playername$选择了$country$ +chat_player_oos;$playername$已断开连接! alice_status_stream;存档处理进度:$value$ alice_play_pending_client;$playername$未准备好 alice_stockpile_button_0_0;国家仓储可以作为您日常经济商业活动的调节物,在?G绿色?W 线看到价格上涨, and ?Rred?W 红线下降, 像往常一样 我 ?Y不是?W 一个折线图所以不总是被注意到: ) @@ -1195,4 +1195,4 @@ ledger_ppp_gdp;GDP(PPP) ledger_ppp_gdp_per_capita;每100万人的GDP(PPP) an_assigned_leader;an assigned leader macro_new_template;新建 -invention;发明 \ No newline at end of file +invention;发明 diff --git a/docs/extensions.md b/docs/extensions.md index 78cb32f15..070d0c75b 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -72,6 +72,8 @@ Additionally, triggers such as technology triggers no longer suffer from having - `if = { ... }`: See below for if-else usage. - `else_if = { ... }`: See below. - `else = { ... }`: See below. +- `add_country_modifier = modifier`: Shorthand for `add_country_modifier = { name = modifier duration = -1 }` +- `add_province_modifier = modifier`: Shorthand for `add_province_modifier = { name = modifier duration = -1 }` As for `build_xxx_in_capital`, the game doesn't allow custom defined buildings to be used in this mode as an effect. diff --git a/src/economy/economy.cpp b/src/economy/economy.cpp index 013ed97d9..f649c267d 100644 --- a/src/economy/economy.cpp +++ b/src/economy/economy.cpp @@ -86,6 +86,26 @@ int32_t previous_price_record_index(sys::state& state) { return ((state.current_date.value >> 4) + price_history_length - 1) % price_history_length; } +int32_t most_recent_gdp_record_index(sys::state& state) { + auto date = state.current_date.to_ymd(state.start_date); + return (date.year * 4 + date.month / 3) % gdp_history_length; +} +int32_t previous_gdp_record_index(sys::state& state) { + auto date = state.current_date.to_ymd(state.start_date); + return ((date.year * 4 + date.month / 3) + gdp_history_length - 1) % gdp_history_length; +} + +float ideal_pound_conversion_rate(sys::state& state, dcon::nation_id n) { + return state.world.nation_get_life_needs_costs(n, state.culture_definitions.primary_factory_worker) + + 0.1f * state.world.nation_get_everyday_needs_costs(n, state.culture_definitions.primary_factory_worker); +} + +float gdp_adjusted(sys::state& state, dcon::nation_id n) { + float raw = state.world.nation_get_gdp(n); + float ideal_pound = ideal_pound_conversion_rate(state, n); + return raw / ideal_pound; +} + float full_spending_cost(sys::state& state, dcon::nation_id n); void populate_army_consumption(sys::state& state); void populate_navy_consumption(sys::state& state); @@ -467,13 +487,15 @@ float pseudo_exp_for_negative(float f) { float get_artisans_multiplier(sys::state& state, dcon::nation_id n) { float multiplier = 0.000001f * state.world.nation_get_everyday_needs_costs(n, state.culture_definitions.artisans); - return 1.f / (multiplier + 1.f); + return 1.f / (multiplier + 1.f); } +constexpr float artisan_baseline_score = 5.f; + float max_artisan_score(sys::state& state, dcon::nation_id n, float multiplier) { auto const csize = state.world.commodity_size(); - float baseline = 10.f / multiplier; + float baseline = artisan_baseline_score / multiplier; float max_score = std::numeric_limits::lowest(); for(uint32_t i = 1; i < csize; ++i) { @@ -494,7 +516,7 @@ float total_artisan_exp_score(sys::state& state, dcon::nation_id n, float multip auto const csize = state.world.commodity_size(); float total = 0.f; - float baseline = 10.f / multiplier; + float baseline = artisan_baseline_score / multiplier; // crude approximation of softmax for(uint32_t i = 1; i < csize; ++i) { @@ -544,9 +566,12 @@ void adjust_artisan_balance(sys::state& state, dcon::nation_id n) { dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) }; if(valid_artisan_good(state, n, cid)) { auto profit = base_artisan_profit(state, n, cid); + //if(profit < 0.f) { + // profit = profit * 10000.f; + //} profits[cid.index()] = profit; } else { - profits[cid.index()] = -256.f / mult / distribution_drift_speed; + profits[cid.index()] = -256.f / mult / distribution_drift_speed * 10.f; } } @@ -557,7 +582,10 @@ void adjust_artisan_balance(sys::state& state, dcon::nation_id n) { for(uint32_t i = 1; i < csize; ++i) { dcon::commodity_id cid{ dcon::commodity_id::value_base_t(i) }; auto& w = state.world.nation_get_artisan_distribution(n, cid); - w = w * 0.5f + distribution_drift_speed * profits[cid.index()] * (1 - get_artisan_distribution_fast(state, n, cid, max_score, total_score, multiplier)); + auto last_distribution = get_artisan_distribution_fast(state, n, cid, max_score, total_score, multiplier); + auto output = state.world.commodity_get_artisan_output_amount(cid); + auto next_score = w * 0.8f + distribution_drift_speed * profits[cid.index()] * (1 - last_distribution) / output; + w = next_score; } } @@ -595,8 +623,8 @@ void initialize(sys::state& state) { state.world.for_each_pop([&](dcon::pop_id p) { auto fp = fatten(state.world, p); - fp.set_life_needs_satisfaction(0.5f); - fp.set_everyday_needs_satisfaction(0.0f); + fp.set_life_needs_satisfaction(1.0f); + fp.set_everyday_needs_satisfaction(0.1f); fp.set_luxury_needs_satisfaction(0.0f); fp.set_savings(savings_buffer.get(fp.get_poptype()) * fp.get_size() / state.defines.alice_needs_scaling_factor); }); @@ -655,7 +683,7 @@ void initialize(sys::state& state) { bool is_mine = state.world.commodity_get_is_mine(main_trade_good); //max size of exploitable land: - auto max_rgo_size = std::ceil(1000.f / state.defines.alice_rgo_per_size_employment + auto max_rgo_size = std::ceil(2000.f / state.defines.alice_rgo_per_size_employment * state.map_state.map_data.province_area[province::to_map_id(p)]); state.world.for_each_commodity([&](dcon::commodity_id c) { @@ -674,7 +702,7 @@ void initialize(sys::state& state) { } auto size_at_the_start_of_the_game = std::ceil(pop_amount / state.defines.alice_rgo_per_size_employment); - auto real_size = std::min(size_at_the_start_of_the_game * 2.f, max_rgo_size); + auto real_size = std::min(size_at_the_start_of_the_game * 1.5f, max_rgo_size); assert(std::isfinite(real_size)); fp.set_rgo_size(real_size); @@ -684,9 +712,10 @@ void initialize(sys::state& state) { float total = 0.f; state.world.for_each_commodity([&](dcon::commodity_id c) { - float current = per_climate_distribution_buffer[climate.value][c.value] - * per_terrain_distribution_buffer[terrain.value][c.value] - * per_continent_distribution_buffer[continent.value][c.value]; + float climate_d = per_climate_distribution_buffer[climate.value][c.value]; + float terrain_d = per_terrain_distribution_buffer[terrain.value][c.value]; + float continent_d = per_continent_distribution_buffer[continent.value][c.value]; + float current = (climate_d + terrain_d) * (climate_d + terrain_d) * continent_d; true_distribution[c.index()] = current; total += current; }); @@ -834,6 +863,10 @@ void update_factory_triggered_modifiers(sys::state& state) { }); } +float subsistence_size(sys::state const& state, dcon::province_id p) { + auto rgo_ownership = state.world.province_get_landowners_share(p) + state.world.province_get_capitalists_share(p); + return state.world.province_get_rgo_size(p) * (1.f - rgo_ownership) * 2.0f; +} float rgo_effective_size(sys::state const& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) { bool is_mine = state.world.commodity_get_is_mine(c); @@ -847,7 +880,8 @@ float rgo_effective_size(sys::state const& state, dcon::nation_id n, dcon::provi // - We calculate its effective size which is its base size x (technology-bonus-to-specific-rgo-good-size + // technology-general-farm-or-mine-size-bonus + provincial-mine-or-farm-size-modifier + 1) - auto sz = state.world.province_get_rgo_max_size_per_good(p, c) + base; + auto rgo_ownership = state.world.province_get_landowners_share(p) + state.world.province_get_capitalists_share(p); + auto sz = state.world.province_get_rgo_max_size_per_good(p, c) * rgo_ownership + base; auto pmod = state.world.province_get_modifier_values(p, is_mine ? sys::provincial_mod_offsets::mine_rgo_size : sys::provincial_mod_offsets::farm_rgo_size); auto nmod = state.world.nation_get_modifier_values(n, is_mine ? sys::national_mod_offsets::mine_rgo_size : sys::national_mod_offsets::farm_rgo_size); auto specific_pmod = state.world.nation_get_rgo_size(n, c); @@ -864,6 +898,10 @@ float rgo_total_effective_size(sys::state & state, dcon::nation_id n, dcon::prov return total; } +float subsistence_max_pseudoemployment(sys::state& state, dcon::nation_id n, dcon::province_id p) { + return state.defines.alice_rgo_per_size_employment * subsistence_size(state, p) * 1.1f; +} + float rgo_total_employment(sys::state & state, dcon::nation_id n, dcon::province_id p) { float total = 0.f; state.world.for_each_commodity([&](dcon::commodity_id c) { @@ -884,48 +922,38 @@ float rgo_total_max_employment(sys::state& state, dcon::nation_id n, dcon::provi return total; } -// here we estimate ratio of land not owned by landowners -// TODO: implement proper land ownership mechanic -float local_free_land(sys::state const& state, dcon::province_id p) { - float landowner_weight = 100.f; - float clergy_weight = 10.f; - float slave_weight = 1.f; - // some of workers are treated as small landowners - float worker_free_weight = 0.8f; - - float slave_pool = state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.slaves)); - float worker_pool = 0.0f; - for(auto wt : state.culture_definitions.rgo_workers) { - worker_pool += state.world.province_get_demographics(p, demographics::to_key(state, wt)); - } - float owners_pool = state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.aristocrat)); - float clergy_pool = state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.clergy)); - - float owners_weight = clergy_pool * clergy_weight + slave_pool * slave_weight + owners_pool * landowner_weight + worker_pool * (1.f - worker_free_weight); - float workers_weight = worker_pool * worker_free_weight; - - float total = workers_weight + owners_weight; +void update_local_subsistence_factor(sys::state & state) { + state.world.execute_parallel_over_province([&](auto ids) { + auto max_subsistence = ve::apply([&](dcon::province_id p) { + return subsistence_max_pseudoemployment(state, state.world.province_get_nation_from_province_ownership(p), p); + }, ids); + auto score = max_subsistence * subsistence_factor / state.defines.alice_rgo_per_size_employment; + auto saturation = state.world.province_get_subsistence_employment(ids) / (max_subsistence + 1.f); + auto quality = (ve::to_float(state.world.province_get_life_rating(ids)) - 10.f) / 10.f; + quality = ve::max(quality, 0.f) + 0.01f; + score = (score * quality) + (subsistence_score_everyday * 0.7f); + auto saturation_inv = (1.0f - saturation); + score = (score * saturation_inv) * saturation_inv * saturation_inv; - if(total < 0.001f) { - return 1.f; - } + state.world.province_set_subsistence_score(ids, score); + }); +} - return workers_weight / total; +float adjusted_subsistence_score(sys::state& state, dcon::province_id p) { + return state.world.province_get_subsistence_score(p) + * state.world.province_get_subsistence_employment(p) + / (state.world.province_get_demographics(p, demographics::total) + 1.f); } -void update_local_subsistence_factor(sys::state & state) { +void update_land_ownership(sys::state& state) { state.world.execute_parallel_over_province([&](auto ids) { - auto score = (state.world.province_get_rgo_size(ids) + 1.f) * subsistence_factor; - auto workers = state.world.province_get_demographics(ids, demographics::to_key(state, state.culture_definitions.farmers)); - workers = workers - state.world.province_get_demographics(ids, demographics::to_key(state, state.culture_definitions.farmers)); - for(auto wt : state.culture_definitions.rgo_workers) { - workers = workers + state.world.province_get_demographics(ids, demographics::to_key(state, wt)); - workers = workers - state.world.province_get_demographics(ids, demographics::to_employment_key(state, wt)); - } - auto quality = (ve::to_float(state.world.province_get_life_rating(ids)) - 10.f) / 10.f; - quality = ve::max(quality, 0.f) + 0.01f; - score = score * quality; - state.world.province_set_subsistence_score(ids, (score / (((score + workers) * 0.5f))) + (subsistence_score_everyday * 0.7f)); + auto local_states = state.world.province_get_state_membership(ids); + auto weight_aristocracy = state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.aristocrat)) * 200.f + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.slaves)); + auto weight_capitalists = state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.capitalists)) * 200.f; + auto weight_population = state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.farmers)) + state.world.state_instance_get_demographics(local_states, demographics::to_key(state, state.culture_definitions.laborers)); + auto total = weight_aristocracy + weight_capitalists + weight_population + 1.0f; + state.world.province_set_landowners_share(ids, weight_aristocracy / total); + state.world.province_set_capitalists_share(ids, weight_capitalists / total); }); } @@ -940,16 +968,14 @@ bool factory_is_profitable(sys::state const& state, dcon::factory_id f) { return state.world.factory_get_unprofitable(f) == false || state.world.factory_get_subsidized(f); } - void update_rgo_employment(sys::state& state) { province::for_each_land_province(state, [&](dcon::province_id p) { auto owner = state.world.province_get_nation_from_province_ownership(p); - auto current_target_employment = 0.f; auto current_employment = 0.f; state.world.for_each_commodity([&](dcon::commodity_id c) { current_employment += state.world.province_get_rgo_employment_per_good(p, c); - current_target_employment += state.world.province_get_rgo_target_employment_per_good(p, c); }); + current_employment += state.world.province_get_subsistence_employment(p); bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(p)); float worker_pool = 0.0f; @@ -959,6 +985,10 @@ void update_rgo_employment(sys::state& state) { float slave_pool = state.world.province_get_demographics(p, demographics::to_key(state, state.culture_definitions.slaves)); float labor_pool = worker_pool + slave_pool; + float total_population = state.world.province_get_demographics(p, demographics::total); + + assert(labor_pool <= total_population); + // update rgo employment per good: //sorting goods by profitability @@ -980,7 +1010,7 @@ void update_rgo_employment(sys::state& state) { }); // distributing workers in almost the same way as factories: - float speed = 0.005f; + float speed = 0.20f; float total_workforce = labor_pool; float max_employment_total = 0.f; @@ -993,7 +1023,7 @@ void update_rgo_employment(sys::state& state) { float target_workforce = std::min(state.world.province_get_rgo_target_employment_per_good(p, c), total_workforce); float current_workforce = state.world.province_get_rgo_employment_per_good(p, c); - float new_employment = current_workforce * (1 - speed) + target_workforce * speed; + float new_employment = std::min(current_workforce * (1 - speed) + target_workforce * speed, total_workforce); total_workforce -= new_employment; new_employment = std::clamp(new_employment, 0.f, max_employment); @@ -1002,6 +1032,14 @@ void update_rgo_employment(sys::state& state) { state.world.province_set_rgo_employment_per_good(p, c, new_employment); } + float subsistence = std::min(subsistence_max_pseudoemployment(state, owner, p), total_workforce); + total_workforce -= subsistence; + total_employed += subsistence; + + state.world.province_set_subsistence_employment(p, subsistence); + + assert(total_employed <= total_population + 1.f); + float employment_ratio = 0.f; if(max_employment_total > 1.f) { employment_ratio = total_employed / (max_employment_total + 1.f); @@ -1199,7 +1237,7 @@ float factory_full_production_quantity(sys::state const& state, dcon::factory_id return throughput_multiplier * output_multiplier * max_production_scale; } -float rgo_efficiency(sys::state const& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) { +float rgo_efficiency(sys::state & state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) { bool is_mine = state.world.commodity_get_is_mine(c); float main_rgo = 1.f; @@ -1222,11 +1260,17 @@ float rgo_efficiency(sys::state const& state, dcon::nation_id n, dcon::province_ is_mine ? sys::national_mod_offsets::mine_rgo_eff : - sys::national_mod_offsets::farm_rgo_eff); + sys::national_mod_offsets::farm_rgo_eff); + + float saturation = state.world.province_get_rgo_employment_per_good(p, c) + / (rgo_max_employment(state, n, p, c) + 1.f); - float result = base_amount * main_rgo * - std::max(0.5f, throughput) * - std::max(0.5f, (1.0f + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_rgo_output) + + float result = base_amount + * main_rgo + * (1.f + 1.0f * (1.f - saturation)) + * std::max(0.5f, throughput) + * state.defines.alice_rgo_boost + * std::max(0.5f, (1.0f + state.world.province_get_modifier_values(p, sys::provincial_mod_offsets::local_rgo_output) + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::rgo_output) + state.world.nation_get_rgo_goods_output(n, c))); @@ -1234,7 +1278,7 @@ float rgo_efficiency(sys::state const& state, dcon::nation_id n, dcon::province_ return result; } -float rgo_full_production_quantity(sys::state const& state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) { +float rgo_full_production_quantity(sys::state & state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c) { /* - We calculate its effective size which is its base size x (technology-bonus-to-specific-rgo-good-size + technology-general-farm-or-mine-size-bonus + provincial-mine-or-farm-size-modifier + 1) @@ -1244,9 +1288,8 @@ float rgo_full_production_quantity(sys::state const& state, dcon::nation_id n, d */ auto eff_size = rgo_effective_size(state, n, p, c); auto val = eff_size * rgo_efficiency(state, n, p, c); - auto rval = val * state.defines.alice_rgo_boost; - assert(rval >= 0.0f && std::isfinite(rval)); - return rval; + assert(val >= 0.0f && std::isfinite(val)); + return val; } float factory_min_input_available( @@ -1631,7 +1674,8 @@ float rgo_desired_worker_norm_profit(sys::state& state, dcon::province_id p, dco ); float aristo_burden_per_worker = aristos_desired_cut / (total_relevant_population + 1); - float subsistence = state.world.province_get_subsistence_score(p); + float subsistence = adjusted_subsistence_score(state, p); + if (subsistence == 0) subsistence = state.world.province_get_subsistence_score(p); float subsistence_life = std::clamp(subsistence, 0.f, subsistence_score_life); subsistence -= subsistence_life; float subsistence_everyday = std::clamp(subsistence, 0.f, subsistence_score_everyday); @@ -1715,7 +1759,7 @@ void update_province_rgo_consumption( float change = (positive_speed - negative_speed) / rgo_effective_size(state, n, p, c); - float discrete_step = (((expected_profit - desired_profit) > 0.f) ? 1.f : -1.f) * 10.f; + float discrete_step = (((expected_profit - desired_profit) > 0.f) ? 1.f : -1.f) * 20.f; change = change / max_production * pops_max / 100.f + discrete_step; @@ -1788,7 +1832,8 @@ void update_national_artisan_consumption(sys::state& state, dcon::nation_id n, f float output_multiplier = std::max(0.1f, state.defines.alice_output_base_factor_artisans + state.world.nation_get_modifier_values(n, sys::national_mod_offsets::artisan_output)); - float max_production_scale = num_artisans * get_artisan_distribution_fast(state, n, cid, max_score, total_score, multiplier) / 10'000.0f * std::max(0.0f, mobilization_impact); + float distribution = get_artisan_distribution_fast(state, n, cid, max_score, total_score, multiplier); + float max_production_scale = num_artisans * distribution / 10'000.0f * std::max(0.0f, mobilization_impact); auto profitability_factor = (output_total * output_multiplier * throughput_multiplier * min_available - input_multiplier * input_total * throughput_multiplier * min_available) / (0.5f * expected_min_wage * (10'000.0f / state.defines.alice_needs_scaling_factor)); @@ -2315,24 +2360,34 @@ void update_pop_consumption(sys::state& state, dcon::nation_id n, float base_dem bool nation_allows_investment = state.world.nation_get_is_civilized(n) && (nation_rules & (issue_rule::pop_build_factory | issue_rule::pop_expand_factory)) != 0; for(auto p : state.world.nation_get_province_ownership(n)) { - float subsistence = state.world.province_get_subsistence_score(p.get_province()); + float subsistence = adjusted_subsistence_score(state, p.get_province()); float subsistence_life = std::clamp(subsistence, 0.f, subsistence_score_life); subsistence -= subsistence_life; float subsistence_everyday = std::clamp(subsistence, 0.f, subsistence_score_everyday); subsistence -= subsistence_everyday; float subsistence_luxury = std::clamp(subsistence, 0.f, subsistence_score_luxury); + subsistence_life /= subsistence_score_life; + subsistence_everyday /= subsistence_score_everyday; + subsistence_luxury /= subsistence_score_luxury; + for(auto pl : state.world.province_get_pop_location(p.get_province())) { auto t = pl.get_pop().get_poptype(); assert(t); auto total_budget = pl.get_pop().get_savings(); auto total_pop = pl.get_pop().get_size(); - float ln_cost = state.world.nation_get_life_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; - float en_cost = state.world.nation_get_everyday_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; - float xn_cost = state.world.nation_get_luxury_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; + //subsistence: + + float ln_to_satisfy = std::max(1.f - subsistence_life, 0.f); + float en_to_satisfy = std::max(1.f - subsistence_everyday, 0.f); + float xn_to_satisfy = std::max(1.f - subsistence_luxury, 0.f); + + float ln_cost = ln_to_satisfy * state.world.nation_get_life_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; + float en_cost = en_to_satisfy * state.world.nation_get_everyday_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; + float xn_cost = xn_to_satisfy * state.world.nation_get_luxury_needs_costs(n, t) * total_pop / state.defines.alice_needs_scaling_factor; - float life_needs_fraction = total_budget >= ln_cost ? 1.0f : total_budget / ln_cost; + float life_needs_fraction = (total_budget >= ln_cost ? ln_to_satisfy : total_budget / ln_cost); total_budget -= ln_cost; //eliminate potential negative number before investment @@ -2349,10 +2404,10 @@ void update_pop_consumption(sys::state& state, dcon::nation_id n, float base_dem total_budget -= total_budget * state.defines.alice_invest_aristocrat; } - float everyday_needs_fraction = total_budget >= en_cost ? 1.0f : std::max(0.0f, total_budget / en_cost); + float everyday_needs_fraction = (total_budget >= en_cost ? en_to_satisfy : std::max(0.0f, total_budget / en_cost)); total_budget -= en_cost; - float luxury_needs_fraction = total_budget >= xn_cost ? 1.0f : std::max(0.0f, total_budget / xn_cost); + float luxury_needs_fraction = (total_budget >= xn_cost ? xn_to_satisfy : std::max(0.0f, total_budget / xn_cost)); total_budget -= xn_cost; // induce demand across all categories @@ -2386,38 +2441,23 @@ void update_pop_consumption(sys::state& state, dcon::nation_id n, float base_dem float old_everyday_to_use_in_demand_calculation = old_everyday; float old_luxury_to_use_in_demand_calculation = old_luxury; - //subsistence: - float final_life_needs_fraction = life_needs_fraction; - float final_everyday_needs_fraction = everyday_needs_fraction; - float final_luxury_needs_fraction = luxury_needs_fraction; - - if(state.world.pop_type_get_is_paid_rgo_worker(t)) { - // unemployed rgo workers participate in subsistence economy instead of starving - float s = pl.get_pop().get_employment() / pl.get_pop().get_size(); - - final_life_needs_fraction = life_needs_fraction * convex_function(s) + subsistence_life * convex_function(1.f - s) / subsistence_score_life; - life_needs_fraction = life_needs_fraction * s; + float final_life_needs_fraction = life_needs_fraction + subsistence_life; + float final_everyday_needs_fraction = everyday_needs_fraction + subsistence_everyday; + float final_luxury_needs_fraction = luxury_needs_fraction + subsistence_luxury; - final_everyday_needs_fraction = everyday_needs_fraction * convex_function(s) + subsistence_everyday * convex_function(1.f - s) / subsistence_score_everyday; - everyday_needs_fraction = everyday_needs_fraction * s; - - final_luxury_needs_fraction = luxury_needs_fraction * convex_function(s) + subsistence_luxury * convex_function(1.f - s) / subsistence_score_luxury; - luxury_needs_fraction = luxury_needs_fraction * s; - - //suppose that old satisfaction was calculated for the same local subsistence conditions and find "raw" satisfaction - // old = raw * s + sub * (1 - s) ## first summand is "raw satisfaction" - old_life_to_use_in_demand_calculation = std::clamp(old_life - subsistence_life / subsistence_score_life * (1.f - s), 0.f, 1.f); - old_everyday_to_use_in_demand_calculation = std::clamp(old_everyday - subsistence_everyday / subsistence_score_everyday * (1.f - s), 0.f, 1.f); - old_luxury_to_use_in_demand_calculation = std::clamp(old_luxury - subsistence_luxury / subsistence_score_luxury * (1.f - s), 0.f, 1.f); - } + //suppose that old satisfaction was calculated for the same local subsistence conditions and find "raw" satisfaction + // old = raw + sub ## first summand is "raw satisfaction" + old_life_to_use_in_demand_calculation = std::clamp(old_life - subsistence_life, 0.f, 1.f); + old_everyday_to_use_in_demand_calculation = std::clamp(old_everyday - subsistence_everyday, 0.f, 1.f); + old_luxury_to_use_in_demand_calculation = std::clamp(old_luxury - subsistence_luxury, 0.f, 1.f); auto result_life = std::clamp(old_life_to_use_in_demand_calculation * 0.9f + life_needs_fraction * 0.1f, 0.f, 1.f); auto result_everyday = std::clamp(old_everyday_to_use_in_demand_calculation * 0.9f + everyday_needs_fraction * 0.1f, 0.f, 1.f); auto result_luxury = std::clamp(old_luxury_to_use_in_demand_calculation * 0.9f + luxury_needs_fraction * 0.1f, 0.f, 1.f); - state.world.pop_set_life_needs_satisfaction(pl.get_pop(), std::clamp(final_life_needs_fraction, 0.f, 1.f)); - state.world.pop_set_everyday_needs_satisfaction(pl.get_pop(), std::clamp(final_everyday_needs_fraction, 0.f, 1.f)); - state.world.pop_set_luxury_needs_satisfaction(pl.get_pop(), std::clamp(final_luxury_needs_fraction, 0.f, 1.f)); + state.world.pop_set_life_needs_satisfaction(pl.get_pop(), std::clamp(old_life * 0.99f + final_life_needs_fraction * 0.01f, 0.f, 1.f)); + state.world.pop_set_everyday_needs_satisfaction(pl.get_pop(), std::clamp(old_everyday * 0.99f + final_everyday_needs_fraction * 0.01f, 0.f, 1.f)); + state.world.pop_set_luxury_needs_satisfaction(pl.get_pop(), std::clamp(old_luxury * 0.99f + final_luxury_needs_fraction * 0.01f, 0.f, 1.f)); ln_demand_vector.get(t) += result_life * total_pop / state.defines.alice_needs_scaling_factor; en_demand_vector.get(t) += result_everyday * total_pop / state.defines.alice_needs_scaling_factor; @@ -2892,6 +2932,7 @@ void daily_update(sys::state& state, bool initiate_buildings) { update scoring for provinces */ + update_land_ownership(state); update_local_subsistence_factor(state); /* @@ -3360,13 +3401,16 @@ void daily_update(sys::state& state, bool initiate_buildings) { /* adjust pop satisfaction based on consumption and subsistence */ - float subsistence = state.world.province_get_subsistence_score(p.get_province()); + float subsistence = adjusted_subsistence_score(state, p.get_province()); float subsistence_life = std::clamp(subsistence, 0.f, subsistence_score_life); subsistence -= subsistence_life; float subsistence_everyday = std::clamp(subsistence, 0.f, subsistence_score_everyday); subsistence -= subsistence_everyday; float subsistence_luxury = std::clamp(subsistence, 0.f, subsistence_score_luxury); + subsistence_life /= subsistence_score_life; + subsistence_everyday /= subsistence_score_everyday; + subsistence_luxury /= subsistence_score_luxury; for(auto pl : p.get_province().get_pop_location()) { auto t = pl.get_pop().get_poptype(); @@ -3375,31 +3419,18 @@ void daily_update(sys::state& state, bool initiate_buildings) { auto en = pl.get_pop().get_everyday_needs_satisfaction(); auto lx = pl.get_pop().get_luxury_needs_satisfaction(); - if(state.world.pop_type_get_is_paid_rgo_worker(t)) { - // unemployed rgo workers participate in subsistence economy instead of starving - float s = pl.get_pop().get_employment() / pl.get_pop().get_size(); + // sat = raw + sub ## first summand is "raw satisfaction" + ln -= subsistence_life; + en -= subsistence_everyday; + lx -= subsistence_luxury; - if(s > 0.99f) { - bool flag = false; - } + ln = std::min(ln, ln_max.get(t)); + en = std::min(en, en_max.get(t)); + lx = std::min(lx, lx_max.get(t)); - // sat = raw * s + sub * (1 - s) ## first summand is "raw satisfaction" - ln -= subsistence_life / subsistence_score_life * (1.f - s); - en -= subsistence_everyday / subsistence_score_everyday * (1.f - s); - lx -= subsistence_luxury / subsistence_score_luxury * (1.f - s); - - ln = std::min(ln, ln_max.get(t)); - en = std::min(en, en_max.get(t)); - lx = std::min(lx, lx_max.get(t)); - - ln += subsistence_life / subsistence_score_life * (1.f - s); - en += subsistence_everyday / subsistence_score_everyday * (1.f - s); - lx += subsistence_luxury / subsistence_score_luxury * (1.f - s); - } else { - ln = std::min(ln, ln_max.get(t)); - en = std::min(en, en_max.get(t)); - lx = std::min(lx, lx_max.get(t)); - } + ln += subsistence_life; + en += subsistence_everyday; + lx += subsistence_luxury; pl.get_pop().set_life_needs_satisfaction(ln); pl.get_pop().set_everyday_needs_satisfaction(en); @@ -3438,8 +3469,20 @@ void daily_update(sys::state& state, bool initiate_buildings) { float total_profit = 0.f; float rgo_owner_profit = 0.f; - float num_rgo_owners = state.world.state_instance_get_demographics(si.get_state(), - demographics::to_key(state, state.culture_definitions.aristocrat)); + float num_capitalist = state.world.state_instance_get_demographics( + si.get_state(), + demographics::to_key(state, state.culture_definitions.capitalists) + ); + + float num_aristocrat = state.world.state_instance_get_demographics( + si.get_state(), + demographics::to_key(state, state.culture_definitions.aristocrat) + ); + + float num_rgo_owners = num_capitalist + num_aristocrat; + + auto capitalists_ratio = num_capitalist / (num_rgo_owners + 1.f); + auto aristocrats_ratio = num_aristocrat / (num_rgo_owners + 1.f); province::for_each_province_in_state_instance(state, si.get_state(), [&](dcon::province_id p) { for(auto f : state.world.province_get_factory_location(p)) { @@ -3501,7 +3544,7 @@ void daily_update(sys::state& state, bool initiate_buildings) { pl.get_pop().set_savings(pl.get_pop().get_savings() + state.inflation * pl.get_pop().get_size() * profit.per_secondary_worker); assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0); } else if(state.culture_definitions.capitalists == pl.get_pop().get_poptype()) { - pl.get_pop().set_savings(pl.get_pop().get_savings() + state.inflation * pl.get_pop().get_size() * profit.per_owner); + pl.get_pop().set_savings(pl.get_pop().get_savings() + state.inflation * pl.get_pop().get_size() * (profit.per_owner + per_rgo_owner_profit)); assert(std::isfinite(pl.get_pop().get_savings()) && pl.get_pop().get_savings() >= 0); } else if(state.culture_definitions.aristocrat == pl.get_pop().get_poptype()) { pl.get_pop().set_savings(pl.get_pop().get_savings() + state.inflation * pl.get_pop().get_size() * per_rgo_owner_profit); diff --git a/src/economy/economy.hpp b/src/economy/economy.hpp index f393e925a..0364e4df6 100644 --- a/src/economy/economy.hpp +++ b/src/economy/economy.hpp @@ -89,10 +89,10 @@ inline std::string_view province_building_type_get_level_text(economy::province_ float get_artisan_distribution_slow(sys::state& state, dcon::nation_id n, dcon::commodity_id c); // base subsistence -inline constexpr float subsistence_factor = 5.0f; -inline constexpr float subsistence_score_life = 20.0f; -inline constexpr float subsistence_score_everyday = 30.0f; -inline constexpr float subsistence_score_luxury = 40.0f; +inline constexpr float subsistence_factor = 10.0f; +inline constexpr float subsistence_score_life = 30.0f; +inline constexpr float subsistence_score_everyday = 50.0f; +inline constexpr float subsistence_score_luxury = 80.0f; inline constexpr float subsistence_score_total = subsistence_score_life + subsistence_score_everyday + subsistence_score_luxury; struct global_economy_state { @@ -120,7 +120,8 @@ constexpr inline dcon::commodity_id money(0); inline constexpr float production_scale_delta = 0.1f; inline constexpr float factory_closed_threshold = 0.0001f; inline constexpr uint32_t price_history_length = 256; -inline constexpr float rgo_owners_cut = 0.20f; +inline constexpr uint32_t gdp_history_length = 128; +inline constexpr float rgo_owners_cut = 0.05f; void presimulate(sys::state& state); @@ -133,6 +134,8 @@ float rgo_full_production_quantity(sys::state const& state, dcon::nation_id n, d float rgo_max_employment(sys::state & state, dcon::nation_id n, dcon::province_id p, dcon::commodity_id c); float rgo_total_max_employment(sys::state& state, dcon::nation_id n, dcon::province_id p); +float subsistence_max_pseudoemployment(sys::state& state, dcon::nation_id n, dcon::province_id p); + float factory_max_employment(sys::state const& state, dcon::factory_id f); bool has_factory(sys::state const& state, dcon::state_instance_id si); @@ -248,6 +251,10 @@ void bound_budget_settings(sys::state& state, dcon::nation_id n); int32_t most_recent_price_record_index(sys::state& state); int32_t previous_price_record_index(sys::state& state); +int32_t most_recent_gdp_record_index(sys::state& state); +int32_t previous_gdp_record_index(sys::state& state); + +float gdp_adjusted(sys::state& state, dcon::nation_id n); void prune_factories(sys::state& state); // get rid of closed factories in full states void go_bankrupt(sys::state& state, dcon::nation_id n); diff --git a/src/gamestate/commands.cpp b/src/gamestate/commands.cpp index 6b6413247..2b7e29490 100644 --- a/src/gamestate/commands.cpp +++ b/src/gamestate/commands.cpp @@ -4447,8 +4447,6 @@ void execute_notify_player_joins(sys::state& state, dcon::nation_id source, sys: ui::chat_message m{}; m.source = source; text::substitution_map sub{}; - auto tag = nations::int_to_tag(state.world.national_identity_get_identifying_int(state.world.nation_get_identity_from_identity_holder(source))); - text::add_to_substitution_map(sub, text::variable_type::x, std::string_view(tag)); text::add_to_substitution_map(sub, text::variable_type::playername, name.to_string_view()); m.body = text::resolve_string_substitution(state, "chat_player_joins", sub); post_chat_message(state, m); @@ -4477,8 +4475,6 @@ void execute_notify_player_leaves(sys::state& state, dcon::nation_id source, boo ui::chat_message m{}; m.source = source; text::substitution_map sub{}; - auto tag = nations::int_to_tag(state.world.national_identity_get_identifying_int(state.world.nation_get_identity_from_identity_holder(source))); - text::add_to_substitution_map(sub, text::variable_type::x, std::string_view(tag)); text::add_to_substitution_map(sub, text::variable_type::playername, state.network_state.map_of_player_names[source.index()].to_string_view()); m.body = text::resolve_string_substitution(state, "chat_player_leaves", sub); post_chat_message(state, m); @@ -4510,8 +4506,6 @@ void execute_notify_player_ban(sys::state& state, dcon::nation_id source, dcon:: ui::chat_message m{}; m.source = source; text::substitution_map sub{}; - auto tag = nations::int_to_tag(state.world.national_identity_get_identifying_int(state.world.nation_get_identity_from_identity_holder(target))); - text::add_to_substitution_map(sub, text::variable_type::x, std::string_view(tag)); text::add_to_substitution_map(sub, text::variable_type::playername, state.network_state.map_of_player_names[target.index()].to_string_view()); m.body = text::resolve_string_substitution(state, "chat_player_ban", sub); post_chat_message(state, m); @@ -4543,8 +4537,6 @@ void execute_notify_player_kick(sys::state& state, dcon::nation_id source, dcon: ui::chat_message m{}; m.source = source; text::substitution_map sub{}; - auto tag = nations::int_to_tag(state.world.national_identity_get_identifying_int(state.world.nation_get_identity_from_identity_holder(target))); - text::add_to_substitution_map(sub, text::variable_type::x, std::string_view(tag)); text::add_to_substitution_map(sub, text::variable_type::playername, state.network_state.map_of_player_names[target.index()].to_string_view()); m.body = text::resolve_string_substitution(state, "chat_player_kick", sub); post_chat_message(state, m); @@ -4595,8 +4587,6 @@ void execute_notify_player_oos(sys::state& state, dcon::nation_id source) { ui::chat_message m{}; m.source = source; text::substitution_map sub{}; - auto tag = nations::int_to_tag(state.world.national_identity_get_identifying_int(state.world.nation_get_identity_from_identity_holder(source))); - text::add_to_substitution_map(sub, text::variable_type::x, std::string_view(tag)); text::add_to_substitution_map(sub, text::variable_type::playername, state.network_state.map_of_player_names[source.index()].to_string_view()); m.body = text::resolve_string_substitution(state, "chat_player_oos", sub); post_chat_message(state, m); diff --git a/src/gamestate/dcon_generated.txt b/src/gamestate/dcon_generated.txt index 0e04d93f8..8b0370036 100644 --- a/src/gamestate/dcon_generated.txt +++ b/src/gamestate/dcon_generated.txt @@ -1534,6 +1534,21 @@ object { type{ array{commodity_id}{float} } tag{ save } } + property{ + name{ landowners_share } + type{ float } + tag{ save } + } + property{ + name{ capitalists_share } + type{ float } + tag{ save } + } + property{ + name{ subsistence_employment } + type{ float } + tag{ save } + } property{ name{ rgo_profit_per_good } type{ array{commodity_id}{float} } @@ -3559,11 +3574,19 @@ object { name{ substates_count } type{ uint16_t } } + property { name{ gdp } type{ float } tag{ save } } + + property { + name { gdp_record } + type{ array{int32_t}{float} } + tag{ save } + } + property { name{ effective_prices } type{ array{commodity_id}{float} } diff --git a/src/gamestate/system_state.cpp b/src/gamestate/system_state.cpp index 2b5b4ade6..ff172eaf6 100644 --- a/src/gamestate/system_state.cpp +++ b/src/gamestate/system_state.cpp @@ -3298,6 +3298,7 @@ void state::load_scenario_data(parsers::error_handler& err, sys::year_month_day world.nation_resize_luxury_needs_weights(world.commodity_size()); world.nation_resize_effective_prices(world.commodity_size()); world.commodity_resize_price_record(economy::price_history_length); + world.nation_resize_gdp_record(economy::gdp_history_length); nations_by_rank.resize(2000); // TODO: take this value directly from the data container: max number of nations nations_by_industrial_score.resize(2000); @@ -4407,6 +4408,13 @@ void state::single_game_tick() { } } + if(((ymd_date.month % 3) == 0) && (ymd_date.day == 1)) { + auto index = economy::most_recent_gdp_record_index(*this); + for(auto n : world.in_nation) { + n.set_gdp_record(index, economy::gdp_adjusted(*this, n)); + } + } + ui_date = current_date; game_state_updated.store(true, std::memory_order::release); diff --git a/src/graphics/opengl_wrapper.cpp b/src/graphics/opengl_wrapper.cpp index 199dbf8f4..1436e62cf 100644 --- a/src/graphics/opengl_wrapper.cpp +++ b/src/graphics/opengl_wrapper.cpp @@ -525,6 +525,17 @@ void bind_vertices_by_rotation(sys::state const& state, ui::rotation r, bool fli } } +void render_simple_rect(sys::state const& state, float x, float y, float width, float height, ui::rotation r, bool flipped, bool rtl) { + glBindVertexArray(state.open_gl.global_square_vao); + bind_vertices_by_rotation(state, r, flipped, rtl); + glUniform4f(parameters::drawing_rectangle, x, y, width, height); + GLuint subroutines[2] = { map_color_modification_to_index(color_modification::none), parameters::linegraph_color }; + glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 2, subroutines); // must set all subroutines in one call + glLineWidth(2.0f); + glUniform3f(parameters::inner_color, 1.f, 0.f, 0.f); + glDrawArrays(GL_LINE_STRIP, 0, 4); +} + void render_textured_rect(sys::state const& state, color_modification enabled, float x, float y, float width, float height, GLuint texture_handle, ui::rotation r, bool flipped, bool rtl) { glBindVertexArray(state.open_gl.global_square_vao); diff --git a/src/graphics/opengl_wrapper.hpp b/src/graphics/opengl_wrapper.hpp index 48a0ce442..3587646a1 100644 --- a/src/graphics/opengl_wrapper.hpp +++ b/src/graphics/opengl_wrapper.hpp @@ -273,7 +273,7 @@ class lines { void set_y(float* v); void bind_buffer(); }; - +void render_simple_rect(sys::state const& state, float x, float y, float width, float height, ui::rotation r, bool flipped); void render_textured_rect(sys::state const& state, color_modification enabled, float x, float y, float width, float height, GLuint texture_handle, ui::rotation r, bool flipped, bool rtl); void render_textured_rect_direct(sys::state const& state, float x, float y, float width, float height, uint32_t handle); diff --git a/src/gui/gui_common_elements.hpp b/src/gui/gui_common_elements.hpp index 9a746a700..ae5ac1784 100644 --- a/src/gui/gui_common_elements.hpp +++ b/src/gui/gui_common_elements.hpp @@ -648,26 +648,15 @@ class nation_total_score_text : public standard_nation_text { class nation_ppp_gdp_text : public standard_nation_text { public: std::string get_text(sys::state& state, dcon::nation_id nation_id) noexcept override { - float costs = - state.world.nation_get_life_needs_costs(nation_id, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_everyday_needs_costs(nation_id, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_luxury_needs_costs(nation_id, state.culture_definitions.primary_factory_worker); - - return text::format_float(state.world.nation_get_gdp(nation_id) / costs); + return text::format_float(economy::gdp_adjusted(state, nation_id)); } }; class nation_ppp_gdp_per_capita_text : public standard_nation_text { public: std::string get_text(sys::state& state, dcon::nation_id nation_id) noexcept override { - float costs = - state.world.nation_get_life_needs_costs(nation_id, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_everyday_needs_costs(nation_id, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_luxury_needs_costs(nation_id, state.culture_definitions.primary_factory_worker); - float population = state.world.nation_get_demographics(nation_id, demographics::total); - - return text::format_float(state.world.nation_get_gdp(nation_id) / costs / population * 1000000.f); + return text::format_float(economy::gdp_adjusted(state, nation_id) / population * 1000000.f); } }; @@ -1579,7 +1568,7 @@ class province_rgo_workers_text : public simple_text_element_base { public: void on_update(sys::state& state) noexcept override { auto province_id = retrieve(state, parent); - set_text(state, text::prettify(int32_t(province::rgo_employment(state, province_id)))); + set_text(state, text::prettify(int32_t(province::land_employment(state, province_id)))); } tooltip_behavior has_tooltip(sys::state& state) noexcept override { @@ -1617,14 +1606,34 @@ class province_rgo_workers_text : public simple_text_element_base { text::add_to_layout_box(state, contents, max_employment_box, max_employment); text::add_to_layout_box(state, contents, expected_profit_box, text::format_money(expected_profit)); - //text::close_layout_box(contents, name_box); - //text::close_layout_box(contents, employment_box); - //text::close_layout_box(contents, max_employment_box); - text::add_to_layout_box(state, contents, base_box, std::string(" ")); text::close_layout_box(contents, base_box); }); + auto rgo_employment = state.world.province_get_subsistence_employment(p); + auto current_employment = int64_t(rgo_employment); + auto max_employment = int64_t(economy::subsistence_max_pseudoemployment(state, n, p)); + auto expected_profit = 0.f; + + auto base_box = text::open_layout_box(contents); + auto name_box = base_box; + name_box.x_size = 75; + auto employment_box = base_box; + employment_box.x_position += 120.f; + auto max_employment_box = base_box; + max_employment_box.x_position += 180.f; + auto expected_profit_box = base_box; + expected_profit_box.x_position += 250.f; + + text::add_to_layout_box(state, contents, name_box, std::string_view("Subsistence")); + + text::add_to_layout_box(state, contents, employment_box, current_employment); + text::add_to_layout_box(state, contents, max_employment_box, max_employment); + text::add_to_layout_box(state, contents, expected_profit_box, text::format_money(expected_profit)); + + text::add_to_layout_box(state, contents, base_box, std::string(" ")); + text::close_layout_box(contents, base_box); + active_modifiers_description(state, contents, p, 15, sys::provincial_mod_offsets::mine_rgo_size, false); if(auto owner = state.world.province_get_nation_from_province_ownership(p); owner) active_modifiers_description(state, contents, owner, 15, sys::national_mod_offsets::mine_rgo_size, false); diff --git a/src/gui/gui_ledger_window.hpp b/src/gui/gui_ledger_window.hpp index 1d1f5ceff..8d0219c05 100644 --- a/src/gui/gui_ledger_window.hpp +++ b/src/gui/gui_ledger_window.hpp @@ -54,6 +54,14 @@ struct ledger_sort { bool reversed = false; }; +struct price_toggle_list { + std::vector data; +}; + +struct nation_toggle_list { + std::vector data; +}; + class ledger_generic_sort_button : public button_element_base { public: std::variant type; @@ -86,7 +94,7 @@ class ledger_prev_button : public generic_settable_elementimpl_set(state, new_payload); } @@ -98,7 +106,7 @@ class ledger_next_button : public generic_settable_element 11) + if(num > 12) num = 1; Cyto::Any new_payload = ledger_page_number{num}; parent->impl_set(state, new_payload); @@ -328,40 +336,22 @@ class ledger_nation_ranking_listbox : public listbox_element_base state.world.nation_get_gdp(b) / b_costs / b_population; + return economy::gdp_adjusted(state, a) / a_population > economy::gdp_adjusted(state, b) / b_population; } }); break; case ledger_sort_type::gdp: std::sort(row_contents.begin(), row_contents.end(), [&](dcon::nation_id a, dcon::nation_id b) { - float a_costs = - state.world.nation_get_life_needs_costs(a, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_everyday_needs_costs(a, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_luxury_needs_costs(a, state.culture_definitions.primary_factory_worker); - float b_costs = - state.world.nation_get_life_needs_costs(b, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_everyday_needs_costs(b, state.culture_definitions.primary_factory_worker) - + state.world.nation_get_luxury_needs_costs(b, state.culture_definitions.primary_factory_worker); - if(lsort.reversed) { - return state.world.nation_get_gdp(a) / a_costs < state.world.nation_get_gdp(b) / b_costs; + return economy::gdp_adjusted(state, a) < economy::gdp_adjusted(state, b); } else { - return state.world.nation_get_gdp(a) / a_costs > state.world.nation_get_gdp(b) / b_costs; + return economy::gdp_adjusted(state, a) > economy::gdp_adjusted(state, b); } }); break; @@ -1986,6 +1976,119 @@ class ledger_commodity_plupp : public tinted_image_element_base { } }; +class ledger_nation_plupp : public tinted_image_element_base { +public: + void on_update(sys::state& state) noexcept override { + auto content = retrieve(state, parent); + color = state.world.nation_get_color(content); + } +}; + +// +// GDP graph +// + +class gdp_graph : public window_element_base { + std::vector graph_per_nation; + const uint32_t graph_length = economy::gdp_history_length; +public: + void on_create(sys::state& state) noexcept override { + window_element_base::on_create(state); + uint32_t total_nations = state.world.nation_size(); + + state.world.for_each_nation([&](dcon::nation_id nation) { + auto ptr = make_element_by_type(state, "ledger_linechart", graph_length); + auto graph = reinterpret_cast(ptr.get()); + auto color = state.world.nation_get_color(nation); + graph->is_coloured = true; + graph->r = sys::red_from_int(color); + graph->g = sys::green_from_int(color); + graph->b = sys::blue_from_int(color); + + graph_per_nation.push_back(graph); + add_child_to_front(std::move(ptr)); + }); + } + void on_update(sys::state& state) noexcept override { + float min = 0.f; + float max = 0.f; + + auto ptr = retrieve< nation_toggle_list*>(state, parent); + if(!ptr) + return; + + state.world.for_each_nation([&](dcon::nation_id nation) { + auto newest_index = economy::most_recent_gdp_record_index(state); + if((*ptr).data[nation.index()]) { + for(uint32_t i = 0; i < graph_length; ++i) { + auto record = state.world.nation_get_gdp_record(nation, (newest_index + economy::gdp_history_length - graph_length + i + 1) % economy::gdp_history_length); + if(record > max) { + max = record; + } + } + } + }); + + state.world.for_each_nation([&](dcon::nation_id nation) { + if(!((*ptr).data[nation.index()])) { + graph_per_nation[nation.index()]->set_visible(state, false); + } else { + graph_per_nation[nation.index()]->set_visible(state, true); + std::vector datapoints(graph_length); + auto newest_index = economy::most_recent_gdp_record_index(state); + + for(uint32_t i = 0; i < graph_length; ++i) { + datapoints[i] = state.world.nation_get_gdp_record(nation, (newest_index + economy::gdp_history_length - graph_length + i + 1) % economy::gdp_history_length); + } + graph_per_nation[nation.index()]->set_data_points(state, datapoints, min, max); + } + }); + } +}; + +class nation_toggle_checkbox : public checkbox_button { +public: + int32_t index; + nation_toggle_checkbox(dcon::nation_id nation_id) { + index = nation_id.index(); + }; + void button_action(sys::state& state) noexcept override { + if(index < 0) return; + auto ptr = retrieve< nation_toggle_list*>(state, parent); + if(!ptr) + return; + (*ptr).data[index] = !(*ptr).data[index]; + state.game_state_updated.store(true, std::memory_order_release); + } + bool is_active(sys::state& state) noexcept override { + if(index < 0) return false; + auto ptr = retrieve< nation_toggle_list*>(state, parent); + if(!ptr) + return false; + return (*ptr).data[index]; + } +}; + +class ledger_nation_entry : public listbox_row_element_base { +public: + std::unique_ptr make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override { + if(name == "nation_ledger_default_textbox") { + return make_element_by_type>(state, id); + } else if(name == "nation_ledger_legend_plupp") { + return make_element_by_type(state, id); + } else if(name == "nation_ledger_legend_checkbox") { + return make_element_by_type(state, id, content); + } else { + return nullptr; + } + } + + void on_update(sys::state& state) noexcept override { + (reinterpret_cast(get_child_by_name(state, "nation_ledger_legend_checkbox")))->index = content.index(); + } +}; + + // // Commodity price // @@ -2016,18 +2119,16 @@ class all_prices_graph : public window_element_base { }); } void on_update(sys::state& state) noexcept override { - uint32_t total_commodities = state.world.commodity_size(); - float min = 0.f; float max = 0.f; - auto ptr = retrieve< std::vector*>(state, parent); + auto ptr = retrieve< price_toggle_list*>(state, parent); if(!ptr) return; state.world.for_each_commodity([&](dcon::commodity_id commodity) { auto newest_index = economy::most_recent_price_record_index(state); - if((*ptr)[commodity.index()]) { + if((*ptr).data[commodity.index()]) { for(uint32_t i = 0; i < graph_length; ++i) { auto price = state.world.commodity_get_price_record(commodity, (newest_index + economy::price_history_length - graph_length + i + 1) % economy::price_history_length); if(price > max) { @@ -2038,7 +2139,7 @@ class all_prices_graph : public window_element_base { }); state.world.for_each_commodity([&](dcon::commodity_id commodity) { - if(!((*ptr)[commodity.index()])) { + if(!((*ptr).data[commodity.index()])) { graph_per_price[commodity.index()]->set_visible(state, false); } else { graph_per_price[commodity.index()]->set_visible(state, true); @@ -2054,7 +2155,6 @@ class all_prices_graph : public window_element_base { } }; - class price_toggle_checkbox : public checkbox_button { public: int32_t index; @@ -2063,18 +2163,18 @@ class price_toggle_checkbox : public checkbox_button { }; void button_action(sys::state& state) noexcept override { if(index < 0) return; - auto ptr = retrieve< std::vector*>(state, parent); + auto ptr = retrieve< price_toggle_list*>(state, parent); if(!ptr) return; - (*ptr)[index] = !(*ptr)[index]; + (*ptr).data[index] = !(*ptr).data[index]; state.game_state_updated.store(true, std::memory_order_release); } bool is_active(sys::state& state) noexcept override { if(index < 0) return false; - auto ptr = retrieve< std::vector*>(state, parent); + auto ptr = retrieve< price_toggle_list*>(state, parent); if(!ptr) return false; - return (*ptr)[index]; + return (*ptr).data[index]; } }; @@ -2111,6 +2211,22 @@ class ledger_commodity_price_listbox : public listbox_element_base { +protected: + std::string_view get_row_element_name() override { + return "ledger_nations_legend_entry"; + } +public: + void on_update(sys::state& state) noexcept override { + row_contents.clear(); + state.world.for_each_nation([&](dcon::nation_id id) { + row_contents.push_back(id); + }); + update(state); + } +}; + class commodity_linegraph_legend_window : public window_element_base { public: std::unique_ptr make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override { @@ -2122,13 +2238,30 @@ class commodity_linegraph_legend_window : public window_element_base { } }; +class nations_linegraph_legend_window : public window_element_base { +public: + std::unique_ptr make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override { + if(name == "legend_nations_list") { + return make_element_by_type(state, id); + } else { + return nullptr; + } + } +}; + class ledger_window : public window_element_base { dcon::gui_def_id listbox_def_id{}; dcon::gui_def_id sort_buttons_window_id{}; all_prices_graph* commodity_linegraph = nullptr; + gdp_graph* gdp_linegraph = nullptr; + commodity_linegraph_legend_window* commodity_linegraph_legend = nullptr; + nations_linegraph_legend_window* gdp_linegraph_legend = nullptr; + image_element_base* commodity_linegraph_image = nullptr; + image_element_base* gdp_linegraph_image = nullptr; + simple_text_element_base* page_number_text = nullptr; simple_text_element_base* ledger_header_text = nullptr; ledger_page_number page_num{int8_t(1)}; @@ -2162,9 +2295,15 @@ class ledger_window : public window_element_base { commodity_linegraph->set_visible(state, false); commodity_linegraph_legend->set_visible(state, false); commodity_linegraph_image->set_visible(state, false); + + + gdp_linegraph->set_visible(state, false); + gdp_linegraph_legend->set_visible(state, false); + gdp_linegraph_image->set_visible(state, false); } - std::vector price_toggle_status; + price_toggle_list price_toggle_status; + nation_toggle_list nation_toggle_status; public: void on_create(sys::state& state) noexcept override { @@ -2172,7 +2311,12 @@ class ledger_window : public window_element_base { uint32_t total_commodities = state.world.commodity_size(); for(uint32_t k = 0; k < total_commodities; ++k) { - price_toggle_status.push_back(true); + price_toggle_status.data.push_back(true); + } + + uint32_t total_nations = state.world.nation_size(); + for(uint32_t k = 0; k < total_nations; ++k) { + nation_toggle_status.data.push_back(true); } { @@ -2286,6 +2430,29 @@ class ledger_window : public window_element_base { add_child_to_front(std::move(ptr)); } + //gdp block + + { + auto def = state.ui_state.defs_by_name.find(state.lookup_key("gdp_ledger_linegraph_bg"))->second.definition; + auto ptr = make_element_by_type(state, def); + gdp_linegraph_image = ptr.get(); + add_child_to_front(std::move(ptr)); + } + + { + auto def = state.ui_state.defs_by_name.find(state.lookup_key("gdp_ledger_linegraphs"))->second.definition; + auto ptr = make_element_by_type(state, def); + gdp_linegraph = ptr.get(); + add_child_to_front(std::move(ptr)); + } + + { + auto def = state.ui_state.defs_by_name.find(state.lookup_key("gdp_ledger_linegraph_legend"))->second.definition; + auto ptr = make_element_by_type(state, def); + gdp_linegraph_legend = ptr.get(); + add_child_to_front(std::move(ptr)); + } + Cyto::Any payload = page_num; impl_set(state, payload); } @@ -2297,7 +2464,7 @@ class ledger_window : public window_element_base { return ptr; } else if(name == "ledger_bg") { return make_element_by_type(state, id); - } else if(name == "ledger_linegraphs") { + } else if(name == "ledger_linegraphs") { // prices block auto ptr = make_element_by_type(state, id); commodity_linegraph = ptr.get(); return ptr; @@ -2383,6 +2550,12 @@ class ledger_window : public window_element_base { commodity_linegraph_legend->set_visible(state, true); commodity_linegraph_image->set_visible(state, true); break; + case 12: + ledger_header_text->set_text(state, text::produce_simple_string(state, "alice_ledger_header_gdp_history")); + gdp_linegraph->set_visible(state, true); + gdp_linegraph_legend->set_visible(state, true); + gdp_linegraph_image->set_visible(state, true); + break; default: break; } @@ -2395,8 +2568,11 @@ class ledger_window : public window_element_base { current_sorting = any_cast>(payload).data; impl_on_update(state); return message_result::consumed; - } else if(payload.holds_type< std::vector*>()) { - payload.emplace*>(&price_toggle_status); + } else if(payload.holds_type< price_toggle_list*>()) { + payload.emplace(&price_toggle_status); + return message_result::consumed; + } else if(payload.holds_type< nation_toggle_list*>()) { + payload.emplace(&nation_toggle_status); return message_result::consumed; } return message_result::unseen; diff --git a/src/gui/gui_province_window.hpp b/src/gui/gui_province_window.hpp index b4f80bc76..0b6cad407 100644 --- a/src/gui/gui_province_window.hpp +++ b/src/gui/gui_province_window.hpp @@ -1248,7 +1248,8 @@ class province_rgo_employment_progress_icon : public opaque_element_base { public: void on_update(sys::state& state) noexcept override { auto province = retrieve(state, parent); - auto employment_ratio = state.world.province_get_rgo_employment(province); + auto max_emp = province::land_maximum_employment(state, province); + auto employment_ratio = province::land_employment(state, province) / (max_emp + 1.f); frame = int32_t(10.f * employment_ratio); } tooltip_behavior has_tooltip(sys::state& state) noexcept override { @@ -1257,8 +1258,8 @@ class province_rgo_employment_progress_icon : public opaque_element_base { void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override { auto prov_id = retrieve(state, parent); auto owner = state.world.province_get_nation_from_province_ownership(prov_id); - auto max_emp = economy::rgo_total_max_employment(state, owner, prov_id); - auto employment_ratio = state.world.province_get_rgo_employment(prov_id); + auto max_emp = province::land_maximum_employment(state, prov_id); + auto employment_ratio = province::land_employment(state, prov_id) / (max_emp + 1.f); bool is_mine = state.world.commodity_get_is_mine(state.world.province_get_rgo(prov_id)); float const min_wage_factor = economy::pop_min_wage_factor(state, owner); @@ -1270,9 +1271,6 @@ class province_rgo_employment_progress_icon : public opaque_element_base { text::add_to_layout_box(state, contents, box, int64_t(std::ceil(employment_ratio * max_emp))); text::add_to_layout_box(state, contents, box, std::string_view{" / "}); text::add_to_layout_box(state, contents, box, int64_t(std::ceil(max_emp))); - - text::add_to_layout_box(state, contents, box, std::string_view{ " / expected min wage: " }); - text::add_to_layout_box(state, contents, box, int64_t(std::ceil(expected_min_wage))); text::close_layout_box(contents, box); } diff --git a/src/parsing/cultures_parsing.cpp b/src/parsing/cultures_parsing.cpp index 533a9e511..8af38a110 100644 --- a/src/parsing/cultures_parsing.cpp +++ b/src/parsing/cultures_parsing.cpp @@ -275,7 +275,7 @@ void make_tech_folder_list(std::string_view name, token_generator& gen, error_ha cat = ::culture::tech_category::military_theory; } else if(is_fixed_token_ci(name.data(), name.data() + name.length(), "population_tech")) { cat = ::culture::tech_category::population; - } else if(is_fixed_token_ci(name.data(), name.data() + name.length(), "diplomacy")) { + } else if(is_fixed_token_ci(name.data(), name.data() + name.length(), "diplomacy_tech")) { cat = ::culture::tech_category::diplomacy; } else if(is_fixed_token_ci(name.data(), name.data() + name.length(), "flavor_tech")) { cat = ::culture::tech_category::flavor; diff --git a/src/parsing/defines.hpp b/src/parsing/defines.hpp index 4f03d12b2..22a95a440 100644 --- a/src/parsing/defines.hpp +++ b/src/parsing/defines.hpp @@ -657,16 +657,16 @@ LUA_DEFINES_LIST_ELEMENT(alice_full_reinforce, 1.000000) \ LUA_DEFINES_LIST_ELEMENT(alice_ai_offensive_strength_overestimate, 1.000000) \ LUA_DEFINES_LIST_ELEMENT(alice_military_score_leadership_factor, 1.000000) \ - LUA_DEFINES_LIST_ELEMENT(alice_lf_needs_scale, 1.000000) \ - LUA_DEFINES_LIST_ELEMENT(alice_ev_needs_scale, 1.000000) \ - LUA_DEFINES_LIST_ELEMENT(alice_lx_needs_scale, 1.500000) \ + LUA_DEFINES_LIST_ELEMENT(alice_lf_needs_scale, 8.000000) \ + LUA_DEFINES_LIST_ELEMENT(alice_ev_needs_scale, 2.000000) \ + LUA_DEFINES_LIST_ELEMENT(alice_lx_needs_scale, 2.000000) \ LUA_DEFINES_LIST_ELEMENT(alice_max_event_iterations, 8.000000) \ LUA_DEFINES_LIST_ELEMENT(alice_needs_scaling_factor, 100000.000000) \ LUA_DEFINES_LIST_ELEMENT(alice_factory_per_level_employment, 10000.0) \ LUA_DEFINES_LIST_ELEMENT(alice_domestic_investment_multiplier, 2.0) \ LUA_DEFINES_LIST_ELEMENT(alice_rgo_boost, 1.25) \ - LUA_DEFINES_LIST_ELEMENT(alice_base_rgo_employment_bonus, 50000.0) \ - LUA_DEFINES_LIST_ELEMENT(alice_base_rgo_efficiency_bonus, 2.0) \ + LUA_DEFINES_LIST_ELEMENT(alice_base_rgo_employment_bonus, 150000.0) \ + LUA_DEFINES_LIST_ELEMENT(alice_base_rgo_efficiency_bonus, 3.0) \ LUA_DEFINES_LIST_ELEMENT(alice_inputs_base_factor_artisans, 1.05) \ LUA_DEFINES_LIST_ELEMENT(alice_output_base_factor_artisans, 0.85) \ LUA_DEFINES_LIST_ELEMENT(alice_inputs_base_factor, 1.0) \ diff --git a/src/provinces/province.cpp b/src/provinces/province.cpp index bc9ba6293..64131e0ba 100644 --- a/src/provinces/province.cpp +++ b/src/provinces/province.cpp @@ -452,8 +452,17 @@ bool can_build_province_building(sys::state& state, dcon::province_id id, dcon:: bool has_an_owner(sys::state& state, dcon::province_id id) { return bool(dcon::fatten(state.world, id).get_nation_from_province_ownership()); } +float land_maximum_employment(sys::state& state, dcon::province_id id) { + auto owner = state.world.province_get_nation_from_province_ownership(id); + return economy::rgo_total_max_employment(state, owner, id) + economy::subsistence_max_pseudoemployment(state, owner, id); +} +float land_employment(sys::state& state, dcon::province_id id) { + auto owner = state.world.province_get_nation_from_province_ownership(id); + return economy::rgo_total_employment(state, owner, id) + state.world.province_get_subsistence_employment(id); +} float rgo_maximum_employment(sys::state& state, dcon::province_id id) { - return economy::rgo_total_max_employment(state, state.world.province_get_nation_from_province_ownership(id), id); + auto owner = state.world.province_get_nation_from_province_ownership(id); + return economy::rgo_total_max_employment(state, owner, id); } float rgo_employment(sys::state& state, dcon::province_id id) { return economy::rgo_total_employment(state, state.world.province_get_nation_from_province_ownership(id), id); diff --git a/src/provinces/province.hpp b/src/provinces/province.hpp index 79bdecefa..b8c0438ce 100644 --- a/src/provinces/province.hpp +++ b/src/provinces/province.hpp @@ -64,6 +64,8 @@ bool state_borders_nation(sys::state& state, dcon::nation_id n, dcon::state_inst dcon::province_id pick_capital(sys::state& state, dcon::nation_id n); +float land_maximum_employment(sys::state& state, dcon::province_id id); +float land_employment(sys::state& state, dcon::province_id id); float rgo_maximum_employment(sys::state& state, dcon::province_id id); float rgo_employment(sys::state& state, dcon::province_id id); float rgo_income(sys::state& state, dcon::province_id id);