Skip to content

Commit

Permalink
Merge pull request #1855 from SneakBug8/main
Browse files Browse the repository at this point in the history
Factory refit feature
  • Loading branch information
schombert authored Jan 19, 2025
2 parents e095ad2 + e3e4b3e commit 7918e57
Show file tree
Hide file tree
Showing 16 changed files with 590 additions and 40 deletions.
58 changes: 58 additions & 0 deletions assets/alice.gui
Original file line number Diff line number Diff line change
Expand Up @@ -5613,4 +5613,62 @@ guiTypes = {
clicksound = click
}
}

windowType = {
name = "factory_refit_window"
position = { x=320 y=-80 }
size = { x=260 y=355 }
horizontalBorder = "0"
orientation="UPPER_LEFT"

iconType =
{
name ="factory_refit_window_bg"
spriteType = "GFX_attach_bg"
position = { x= 0 y = 0 }
Orientation = "UPPER_LEFT"
}

listboxType = {
name ="factory_refit_type_list"
position = { x = 10 y = 10 }
backGround=""
size = { x=260 y =340 }
Orientation = "UPPER_LEFT"
spacing = 1
scrollbartype = "standardlistbox_slider"
borderSize = {x = 0 y = 0}
}
}

windowType = {
name = "factory_refit_type_item"
position = { x=0 y=0 }
size = { x=220 y=40 }
horizontalBorder = "0"
orientation="UPPER_LEFT"

iconType = {
name ="factory_type_icon"
spriteType = "GFX_resources"
position = { x= 0 y = 0 }
}

guiButtonType = {
name = "factory_type_select"
position = { x = 40 y = 0 }
size = { x=180 y=40 }
quadTextureSprite ="GFX_diplo_wargoal_button"
buttonFont = "vic_18_black"
buttonText = "Test"
clicksound = click
}
}

guiButtonType = {
name = "factory_refit_button"
position = { x = 25 y = 15 }
quadTextureSprite ="GFX_unit_upgrade_button"
extends="factory_info"
}
}
6 changes: 5 additions & 1 deletion assets/localisation/en-US/alice.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,10 @@ CANCEL_WARSUBSIDIES_WE_ACCEPT_LOG;$ACTOR$ stopped giving subsidies to us;
CANCEL_WARSUBSIDIES_OTHER_ACCEPT_LOG;$ACTOR$ stopped giving subsidies to $RECIPIENT$;
CANCEL_WARSUBSIDIES_DESC;Cancel monetary help to this country;
CANCEL_WARSUBSIDIES_BUTTON;Cancel Subsidies;
production_refit_factory_tooltip_1;Refit ?Y$what$?! to a different production line
production_refit_factory_tooltip_2;Refit ?Y$what$?! into ?Y$name$?!
factory_refit_cost;$what$: ?Y$val$?! (?Y$value$?!)
factory_refit_cost_total;Total: ?Y$value$?!
alice_budget_scaled_16;Diplomatic interest: ?G$value$
alice_budget_scaled_17;Gold production: ?G$value$
alice_budget_scaled_net;Net revenue: ?Y$value$
Expand Down Expand Up @@ -1361,4 +1365,4 @@ alice_budget_debt_enable;Enable
alice_budget_tariffs_import;Import Duties
alice_budget_tariffs_export;Export Duties
alice_budget_overseas_maintanance;Colonial
alice_budget_social_spending;Benefits
alice_budget_social_spending;Benefits
3 changes: 3 additions & 0 deletions docs/Devlogs/v1.2.1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Assembled by SneakBug8
## by Schombert

- Complete rework of macrobuilder window UI
- Complete rework of budget window UI

## by Peter

Expand Down Expand Up @@ -42,6 +43,8 @@ War justification for state-level CBs (such as demand state) requires selection
- Regiment/ship types must be researched and available to the owner nation.
- Small ships cannot be converted into capitol (big) ships.

**Player password in MP.** To protect himself from impersonators player can set a password in launcher. Password is passed to the PA game as a cmd argument. Client sends password to the server in plain form. If player is known, salt is taken from DCON and hashes are compared to check whether to drop connection. If player is new, hash and salt are stored in DCON. If player previously didn't have a password and sets one in Launcher - it'll update password. In persistent mode, hash and salt are stored in playerlist csv file.

Other bits and pieces:
- New tooltips for private investment pool under current treasury in the topbar
- Expanded Web API
Expand Down
164 changes: 147 additions & 17 deletions src/economy/economy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3107,6 +3107,82 @@ float global_factory_construction_time_modifier(sys::state& state) {
return 0.1f;
}

economy::commodity_set calculate_factory_refit_goods_cost(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid, dcon::factory_type_id from, dcon::factory_type_id to) {
auto& from_cost = state.world.factory_type_get_construction_costs(from);
auto& to_cost = state.world.factory_type_get_construction_costs(to);

auto level = 1;

auto d = state.world.state_instance_get_definition(sid);
auto o = state.world.state_instance_get_nation_from_state_ownership(sid);
for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
if(p.get_province().get_nation_from_province_ownership() == o) {
for(auto f : p.get_province().get_factory_location()) {
if(f.get_factory().get_building_type() == from) {
level = f.get_factory().get_level();
}
}
}
}

// Refit cost = (to_cost) - (from_cost) + (0.1f * to_cost)
float refit_mod = 1.0f + state.defines.alice_factory_refit_cost_modifier;

economy::commodity_set res;

// First take 110% of to_cost as a baseline
if(!(n == state.local_player_nation && state.cheat_data.instant_industry)) {
for(uint32_t j = 0; j < commodity_set::set_size; ++j) {
if(to_cost.commodity_type[j]) {
res.commodity_type[j] = to_cost.commodity_type[j];
res.commodity_amounts[j] = to_cost.commodity_amounts[j] * refit_mod * level;
} else {
break;
}
}
}

// Substract from_cost to represent refit discount
if(!(n == state.local_player_nation && state.cheat_data.instant_industry)) {
for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
if(!from_cost.commodity_type[i]) {
break;
}

auto from_amount = from_cost.commodity_amounts[i] * level;
auto from_commodity = from_cost.commodity_type[i];

for(uint32_t j = 0; i < commodity_set::set_size; ++j) {
if(!res.commodity_type[j]) {
break;
}

if(res.commodity_type[j] == from_commodity) {
res.commodity_amounts[j] = std::max(res.commodity_amounts[j] - from_amount, 0.f);
}
}
}
}

return res;
}
float calculate_factory_refit_money_cost(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid, dcon::factory_type_id from, dcon::factory_type_id to) {
auto goods_cost = calculate_factory_refit_goods_cost(state, n, sid, from, to);

float admin_eff = state.world.nation_get_administrative_efficiency(n);
float admin_cost_factor = 2.0f - admin_eff;
float factory_mod = state.world.nation_get_modifier_values(n, sys::national_mod_offsets::factory_cost) + 1.0f;

auto total = 0.0f;
for(uint32_t i = 0; i < economy::commodity_set::set_size; i++) {
if(goods_cost.commodity_type[i]) {
total += economy::price(state, sid, goods_cost.commodity_type[i]) * goods_cost.commodity_amounts[i] * factory_mod * admin_cost_factor;
}
}

return total;
}

void populate_construction_consumption(sys::state& state) {

uint32_t total_commodities = state.world.commodity_size();
Expand Down Expand Up @@ -3308,7 +3384,7 @@ void populate_construction_consumption(sys::state& state) {
if(owner && !c.get_is_pop_project()) {
float& base_budget = current_budget.get(owner);
float budget_limit = total_budget.get(owner) / float(std::max(1, going_constructions.get(owner)));
auto& base_cost = c.get_type().get_construction_costs();
auto base_cost = (c.get_refit_target() ? calculate_factory_refit_goods_cost(state, owner, c.get_state(), c.get_type(), c.get_refit_target()) : c.get_type().get_construction_costs());
auto& current_purchased = c.get_purchased_goods();

float construction_time =
Expand Down Expand Up @@ -8596,33 +8672,78 @@ float unit_construction_progress(sys::state& state, dcon::province_naval_constru

void add_factory_level_to_state(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id t, bool is_upgrade) {

if(is_upgrade) {
auto d = state.world.state_instance_get_definition(s);
auto o = state.world.state_instance_get_nation_from_state_ownership(s);
for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
if(p.get_province().get_nation_from_province_ownership() == o) {
for(auto f : p.get_province().get_factory_location()) {
if(f.get_factory().get_building_type() == t) {
auto factory_level = f.get_factory().get_level();
auto new_factory_level = std::min(float(std::numeric_limits<uint8_t>::max()), float(factory_level) + 1.f);
f.get_factory().get_level() = uint8_t(new_factory_level);
return;
}
// Since construction may be queued together with refit, check if there is factory to add level to
auto d = state.world.state_instance_get_definition(s);
auto o = state.world.state_instance_get_nation_from_state_ownership(s);
for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
if(p.get_province().get_nation_from_province_ownership() == o) {
for(auto f : p.get_province().get_factory_location()) {
if(f.get_factory().get_building_type() == t) {
auto factory_level = f.get_factory().get_level();
auto new_factory_level = std::min(float(std::numeric_limits<uint8_t>::max()), float(factory_level) + 1.f);
f.get_factory().get_level() = uint8_t(new_factory_level);
return;
}
}
}
}

// Only then create new factory
auto state_cap = state.world.state_instance_get_capital(s);
auto new_fac = fatten(state.world, state.world.create_factory());
new_fac.set_building_type(t);
new_fac.set_level(uint8_t(1));
new_fac.set_unqualified_employment(0.33f);
new_fac.set_primary_employment(0.33f);
new_fac.set_secondary_employment(0.33f);

state.world.try_create_factory_location(new_fac, state_cap);
}

void change_factory_type_in_state(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id t, dcon::factory_type_id refit_target) {
assert(refit_target);
auto d = state.world.state_instance_get_definition(s);
auto o = state.world.state_instance_get_nation_from_state_ownership(s);

dcon::factory_id factory_target;

// Find factory in question
for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
if(p.get_province().get_nation_from_province_ownership() == o) {
for(auto f : p.get_province().get_factory_location()) {
if(f.get_factory().get_building_type() == t) {
factory_target = f.get_factory();
}
}
}
}

// Find existing factories to sum
for(auto p : state.world.state_definition_get_abstract_state_membership(d))
if(p.get_province().get_nation_from_province_ownership() == o)
for(auto f : p.get_province().get_factory_location())
if(f.get_factory().get_building_type() == refit_target) {
auto factory_level_1 = f.get_factory().get_level();
auto factory_level_2 = state.world.factory_get_level(factory_target);
auto new_factory_level = std::min(float(std::numeric_limits<uint8_t>::max()), float(factory_level_1) + float(factory_level_2));
f.get_factory().get_level() = uint8_t(new_factory_level);

state.world.delete_factory(factory_target);
return;
}

// Change type of the given factory
for(auto p : state.world.state_definition_get_abstract_state_membership(d)) {
if(p.get_province().get_nation_from_province_ownership() == o) {
for(auto f : p.get_province().get_factory_location()) {
if(f.get_factory().get_building_type() == t) {
f.get_factory().set_building_type(refit_target);
return;
}
}
}
}
}

void resolve_constructions(sys::state& state) {

for(auto c : state.world.in_province_land_construction) {
Expand Down Expand Up @@ -8791,7 +8912,7 @@ void resolve_constructions(sys::state& state) {
for(auto c : state.world.in_state_building_construction) {
auto n = state.world.state_building_construction_get_nation(c);
auto type = state.world.state_building_construction_get_type(c);
auto& base_cost = state.world.factory_type_get_construction_costs(type);
auto base_cost = (c.get_refit_target()) ? calculate_factory_refit_goods_cost(state, n, c.get_state(), c.get_type(), c.get_refit_target()) : state.world.factory_type_get_construction_costs(type);
auto& current_purchased = state.world.state_building_construction_get_purchased_goods(c);

if(!state.world.state_building_construction_get_is_pop_project(c)) {
Expand All @@ -8812,7 +8933,12 @@ void resolve_constructions(sys::state& state) {
}
}
}
if(all_finished) {
if(all_finished && c.get_refit_target()) {
change_factory_type_in_state(state, state.world.state_building_construction_get_state(c), type,
c.get_refit_target());
state.world.delete_state_building_construction(c);
}
else if (all_finished) {
add_factory_level_to_state(state, state.world.state_building_construction_get_state(c), type,
state.world.state_building_construction_get_is_upgrade(c));
state.world.delete_state_building_construction(c);
Expand All @@ -8833,7 +8959,11 @@ void resolve_constructions(sys::state& state) {
}
}
}
if(all_finished) {
if(all_finished && c.get_refit_target()) {
change_factory_type_in_state(state, state.world.state_building_construction_get_state(c), type,
c.get_refit_target());
state.world.delete_state_building_construction(c);
} else if(all_finished) {
add_factory_level_to_state(state, state.world.state_building_construction_get_state(c), type,
state.world.state_building_construction_get_is_upgrade(c));

Expand Down
3 changes: 3 additions & 0 deletions src/economy/economy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,11 @@ struct new_factory {
struct upgraded_factory {
float progress = 0.0f;
dcon::factory_type_id type;
dcon::factory_type_id target_type;
};

economy::commodity_set calculate_factory_refit_goods_cost(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid, dcon::factory_type_id from, dcon::factory_type_id to);
float calculate_factory_refit_money_cost(sys::state& state, dcon::nation_id n, dcon::state_instance_id sid, dcon::factory_type_id from, dcon::factory_type_id to);
bool state_contains_constructed_factory(sys::state& state, dcon::state_instance_id si, dcon::factory_type_id ft);
bool state_contains_factory(sys::state& state, dcon::state_instance_id s, dcon::factory_type_id ft);
int32_t state_factory_count(sys::state& state, dcon::state_instance_id sid, dcon::nation_id n);
Expand Down
9 changes: 5 additions & 4 deletions src/economy/economy_templates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace economy {
template<typename F>
void for_each_new_factory(sys::state& state, dcon::state_instance_id s, F&& func) {
for(auto st_con : state.world.state_instance_get_state_building_construction(s)) {
if(!st_con.get_is_upgrade()) {
if(!st_con.get_is_upgrade() && !st_con.get_refit_target()) {
float admin_eff = state.world.nation_get_administrative_efficiency(st_con.get_nation());
float factory_mod = state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_cost) + 1.0f;
float pop_factory_mod = std::max(0.1f, state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_owner_cost));
Expand All @@ -29,22 +29,23 @@ void for_each_new_factory(sys::state& state, dcon::state_instance_id s, F&& func
template<typename F>
void for_each_upgraded_factory(sys::state& state, dcon::state_instance_id s, F&& func) {
for(auto st_con : state.world.state_instance_get_state_building_construction(s)) {
if(st_con.get_is_upgrade()) {
if(st_con.get_is_upgrade() || st_con.get_refit_target()) {
float admin_eff = state.world.nation_get_administrative_efficiency(st_con.get_nation());
float factory_mod = state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_cost) + 1.0f;
float pop_factory_mod = std::max(0.1f, state.world.nation_get_modifier_values(st_con.get_nation(), sys::national_mod_offsets::factory_owner_cost));
float admin_cost_factor = (st_con.get_is_pop_project() ? pop_factory_mod : (2.0f - admin_eff)) * factory_mod;
float refit_discount = (st_con.get_refit_target()) ? state.defines.alice_factory_refit_cost_modifier : 1.0f;

float total = 0.0f;
float purchased = 0.0f;
auto& goods = state.world.factory_type_get_construction_costs(st_con.get_type());

for(uint32_t i = 0; i < commodity_set::set_size; ++i) {
total += goods.commodity_amounts[i] * admin_cost_factor;
total += goods.commodity_amounts[i] * admin_cost_factor * refit_discount;
purchased += st_con.get_purchased_goods().commodity_amounts[i];
}

func(upgraded_factory{total > 0.0f ? purchased / total : 0.0f, st_con.get_type().id});
func(upgraded_factory{total > 0.0f ? purchased / total : 0.0f, st_con.get_type().id, st_con.get_refit_target().id});
}
}
}
Expand Down
Loading

0 comments on commit 7918e57

Please sign in to comment.