Skip to content

Commit 2c8c7be

Browse files
committed
Implement building restrictions
1 parent 2775e5c commit 2c8c7be

14 files changed

Lines changed: 380 additions & 148 deletions

src/openvic-simulation/country/CountryInstance.cpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "openvic-simulation/defines/EconomyDefines.hpp"
1818
#include "openvic-simulation/defines/MilitaryDefines.hpp"
1919
#include "openvic-simulation/diplomacy/CountryRelation.hpp"
20+
#include "openvic-simulation/economy/BuildingLevel.hpp"
2021
#include "openvic-simulation/economy/BuildingType.hpp"
2122
#include "openvic-simulation/economy/GoodInstance.hpp"
2223
#include "openvic-simulation/economy/production/ProductionType.hpp"
@@ -275,7 +276,7 @@ CountryInstance::CountryInstance(
275276
update_parties_for_votes(new_country_definition);
276277

277278
for (BuildingType const& building_type : building_type_unlock_levels.get_keys()) {
278-
if (building_type.is_default_enabled()) {
279+
if (building_type.is_enabled_by_default) {
279280
unlock_building_type(building_type);
280281
}
281282
}
@@ -335,6 +336,45 @@ bool CountryInstance::is_neighbour(CountryInstance const& country) const {
335336
return neighbouring_countries.contains(&country);
336337
}
337338

339+
bool CountryInstance::may_build_in(const BuildingRestrictionCategory restriction_category, ProvinceInstance const& location) const {
340+
CountryInstance const* const owner_ptr = location.get_owner();
341+
342+
if (owner_ptr == nullptr) {
343+
//Can't build in uncolonised provinces
344+
return false;
345+
}
346+
CountryInstance const& owner = *owner_ptr;
347+
348+
if (owner == *this) {
349+
switch(restriction_category) {
350+
case BuildingRestrictionCategory::UNRESTRICTED:
351+
return true;
352+
case BuildingRestrictionCategory::INFRASTRUCTURE:
353+
return rule_set.may_expand_infrastructure_domestically();
354+
case BuildingRestrictionCategory::FACTORY:
355+
return rule_set.may_build_factory_domestically();
356+
}
357+
}
358+
359+
if (is_at_war_with(owner)) {
360+
//Not allowed to build in hostile lands.
361+
return false;
362+
}
363+
364+
if (!owner.rule_set.foreigners_may_invest()) {
365+
return false;
366+
}
367+
368+
switch(restriction_category) {
369+
case BuildingRestrictionCategory::UNRESTRICTED:
370+
return false; //For example you can't invest in foreign forts.
371+
case BuildingRestrictionCategory::INFRASTRUCTURE:
372+
return rule_set.may_invest_in_expanding_infrastructure_abroad();
373+
case BuildingRestrictionCategory::FACTORY:
374+
return rule_set.may_invest_in_building_factory_abroad();
375+
}
376+
}
377+
338378
CountryRelationManager::relation_value_type CountryInstance::get_relations_with(CountryInstance const& country) const {
339379
return country_relations_manager.get_country_relation(this, &country);
340380
}
@@ -870,12 +910,13 @@ bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const {
870910
}
871911

872912
bool CountryInstance::modify_building_type_unlock(
873-
BuildingType const& building_type, technology_unlock_level_t unlock_level_change
913+
BuildingType const& building_type, technology_unlock_level_t tech_unlock_level_change
874914
) {
875-
technology_unlock_level_t& unlock_level = building_type_unlock_levels.at(building_type);
915+
building_level_t& unlock_level = building_type_unlock_levels.at(building_type);
916+
building_level_t unlock_level_change = building_level_t(type_safe::get(tech_unlock_level_change));
876917

877918
// This catches subtracting below 0 or adding above the int types maximum value
878-
if (unlock_level + unlock_level_change < 0) {
919+
if (unlock_level + unlock_level_change < building_level_t(0)) {
879920
spdlog::error_s(
880921
"Attempted to change unlock level for building type {} in country {} to invalid value: current level = {}, change = {}, invalid new value = {}",
881922
building_type, *this, unlock_level, unlock_level_change,
@@ -886,8 +927,8 @@ bool CountryInstance::modify_building_type_unlock(
886927

887928
unlock_level += unlock_level_change;
888929

889-
if (building_type.get_production_type() != nullptr) {
890-
good_instance_manager.enable_good(building_type.get_production_type()->output_good);
930+
if (building_type.production_type != nullptr) {
931+
good_instance_manager.enable_good(building_type.production_type->output_good);
891932
}
892933

893934
return true;
@@ -897,8 +938,12 @@ bool CountryInstance::unlock_building_type(BuildingType const& building_type) {
897938
return modify_building_type_unlock(building_type, technology_unlock_level_t { 1 });
898939
}
899940

941+
building_level_t const& CountryInstance::get_building_type_unlock_levels(BuildingType const& building_type) const {
942+
return building_type_unlock_levels.at(building_type);
943+
}
944+
900945
bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const {
901-
return building_type_unlock_levels.at(building_type) > 0;
946+
return building_type_unlock_levels.at(building_type) > building_level_t(0);
902947
}
903948

904949
bool CountryInstance::modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change) {

src/openvic-simulation/country/CountryInstance.hpp

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <fmt/base.h>
66

77
#include "openvic-simulation/diplomacy/CountryRelation.hpp"
8+
#include "openvic-simulation/economy/BuildingLevel.hpp"
9+
#include "openvic-simulation/economy/BuildingRestrictionCategory.hpp"
810
#include "openvic-simulation/military/CombatWidth.hpp"
911
#include "openvic-simulation/military/UnitBranchedGetterMacro.hpp"
1012
#include "openvic-simulation/modifier/ModifierSum.hpp"
@@ -155,7 +157,7 @@ namespace OpenVic {
155157
memory::vector<std::pair<CountryInstance const*, fixed_point_t>> SPAN_PROPERTY(industrial_power_from_investments);
156158
size_t PROPERTY(industrial_rank, 0);
157159
fixed_point_map_t<CountryInstance const*> PROPERTY(foreign_investments);
158-
OV_IFLATMAP_PROPERTY(BuildingType, technology_unlock_level_t, building_type_unlock_levels);
160+
OV_IFLATMAP_PROPERTY(BuildingType, building_level_t, building_type_unlock_levels);
159161
// TODO - total amount of each good produced
160162

161163
/* Budget */
@@ -410,57 +412,58 @@ namespace OpenVic {
410412
OV_UNIT_BRANCHED_GETTER(get_leaders, generals, admirals);
411413
OV_UNIT_BRANCHED_GETTER_CONST(get_leaders, generals, admirals);
412414

413-
inline size_t get_general_count() const {
415+
[[nodiscard]] inline size_t get_general_count() const {
414416
return generals.size();
415417
}
416-
inline bool has_generals() const {
418+
[[nodiscard]] inline bool has_generals() const {
417419
return !generals.empty();
418420
}
419-
inline size_t get_admiral_count() const {
421+
[[nodiscard]] inline size_t get_admiral_count() const {
420422
return admirals.size();
421423
}
422-
inline bool has_admirals() const {
424+
[[nodiscard]] inline bool has_admirals() const {
423425
return !admirals.empty();
424426
}
425-
inline size_t get_leader_count() const {
427+
[[nodiscard]] inline size_t get_leader_count() const {
426428
return get_general_count() + get_admiral_count();
427429
}
428-
inline bool has_leaders() const {
430+
[[nodiscard]] inline bool has_leaders() const {
429431
return has_generals() || has_admirals();
430432
}
431-
inline size_t get_army_count() const {
433+
[[nodiscard]] inline size_t get_army_count() const {
432434
return armies.size();
433435
}
434-
inline bool has_armies() const {
436+
[[nodiscard]] inline bool has_armies() const {
435437
return !armies.empty();
436438
}
437-
inline size_t get_navy_count() const {
439+
[[nodiscard]] inline size_t get_navy_count() const {
438440
return navies.size();
439441
}
440-
inline bool has_navies() const {
442+
[[nodiscard]] inline bool has_navies() const {
441443
return !navies.empty();
442444
}
443445

444-
std::string_view get_identifier() const;
446+
[[nodiscard]] std::string_view get_identifier() const;
445447

446-
bool exists() const;
447-
bool is_rebel_country() const;
448-
bool is_civilised() const;
449-
bool can_colonise() const;
450-
bool is_great_power() const;
451-
bool is_secondary_power() const;
452-
bool is_at_war() const;
453-
bool is_neighbour(CountryInstance const& country) const;
448+
[[nodiscard]] bool exists() const;
449+
[[nodiscard]] bool is_rebel_country() const;
450+
[[nodiscard]] bool is_civilised() const;
451+
[[nodiscard]] bool can_colonise() const;
452+
[[nodiscard]] bool is_great_power() const;
453+
[[nodiscard]] bool is_secondary_power() const;
454+
[[nodiscard]] bool is_at_war() const;
455+
[[nodiscard]] bool is_neighbour(CountryInstance const& country) const;
456+
[[nodiscard]] bool may_build_in(const BuildingRestrictionCategory restriction_category, ProvinceInstance const& location) const;
454457

455458
// Double-sided diplomacy functions
456459

457460
CountryRelationManager::relation_value_type get_relations_with(CountryInstance const& country) const;
458461
void set_relations_with(CountryInstance& country, CountryRelationManager::relation_value_type relations);
459462

460-
bool has_alliance_with(CountryInstance const& country) const;
463+
[[nodiscard]] bool has_alliance_with(CountryInstance const& country) const;
461464
void set_alliance_with(CountryInstance& country, bool alliance = true);
462465

463-
bool is_at_war_with(CountryInstance const& country) const;
466+
[[nodiscard]] bool is_at_war_with(CountryInstance const& country) const;
464467
// Low-level setter function, should not be used to declare or join wars
465468
// Should generally be the basis for higher-level war functions
466469
void set_at_war_with(CountryInstance& country, bool at_war = true);
@@ -469,16 +472,16 @@ namespace OpenVic {
469472

470473
// Only detects military access diplomacy, do not use to validate troop movement
471474
// Prefer can_units_enter
472-
bool has_military_access_to(CountryInstance const& country) const;
475+
[[nodiscard]] bool has_military_access_to(CountryInstance const& country) const;
473476
void set_military_access_to(CountryInstance& country, bool access = true);
474477

475-
bool is_sending_war_subsidy_to(CountryInstance const& country) const;
478+
[[nodiscard]] bool is_sending_war_subsidy_to(CountryInstance const& country) const;
476479
void set_sending_war_subsidy_to(CountryInstance& country, bool sending = true);
477480

478-
bool is_commanding_units(CountryInstance const& country) const;
481+
[[nodiscard]] bool is_commanding_units(CountryInstance const& country) const;
479482
void set_commanding_units(CountryInstance& country, bool commanding = true);
480483

481-
bool has_vision_of(CountryInstance const& country) const;
484+
[[nodiscard]] bool has_vision_of(CountryInstance const& country) const;
482485
void set_has_vision_of(CountryInstance& country, bool vision = true);
483486

484487
CountryRelationManager::OpinionType get_opinion_of(CountryInstance const& country) const;
@@ -498,8 +501,8 @@ namespace OpenVic {
498501
std::optional<Date> get_embass_banned_from_date(CountryInstance const& country) const;
499502
void set_embassy_banned_from(CountryInstance& country, Date until);
500503

501-
bool can_army_units_enter(CountryInstance const& country) const;
502-
bool can_navy_units_enter(CountryInstance const& country) const;
504+
[[nodiscard]] bool can_army_units_enter(CountryInstance const& country) const;
505+
[[nodiscard]] bool can_navy_units_enter(CountryInstance const& country) const;
503506

504507
// These functions take "std::string const&" rather than "std::string_view" as they're only used with script arguments
505508
// which are always stored as "std::string"s and it significantly simplifies mutable value access.
@@ -545,36 +548,36 @@ namespace OpenVic {
545548
bool add_leader(LeaderInstance& leader);
546549
bool remove_leader(LeaderInstance const& leader);
547550

548-
bool has_leader_with_name(std::string_view name) const;
551+
[[nodiscard]] bool has_leader_with_name(std::string_view name) const;
549552

550553
template<unit_branch_t Branch>
551554
bool modify_unit_type_unlock(UnitTypeBranched<Branch> const& unit_type, technology_unlock_level_t unlock_level_change);
552555

553556
bool modify_unit_type_unlock(UnitType const& unit_type, technology_unlock_level_t unlock_level_change);
554557
bool unlock_unit_type(UnitType const& unit_type);
555-
bool is_unit_type_unlocked(UnitType const& unit_type) const;
558+
[[nodiscard]] bool is_unit_type_unlocked(UnitType const& unit_type) const;
556559

557560
bool modify_building_type_unlock(
558561
BuildingType const& building_type, technology_unlock_level_t unlock_level_change
559562
);
560563
bool unlock_building_type(BuildingType const& building_type);
561-
bool is_building_type_unlocked(BuildingType const& building_type) const;
564+
[[nodiscard]] bool is_building_type_unlocked(BuildingType const& building_type) const;
562565

563566
bool modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change);
564567
bool unlock_crime(Crime const& crime);
565-
bool is_crime_unlocked(Crime const& crime) const;
568+
[[nodiscard]] bool is_crime_unlocked(Crime const& crime) const;
566569

567570
bool modify_gas_attack_unlock(technology_unlock_level_t unlock_level_change);
568571
bool unlock_gas_attack();
569-
bool is_gas_attack_unlocked() const;
572+
[[nodiscard]] bool is_gas_attack_unlocked() const;
570573

571574
bool modify_gas_defence_unlock(technology_unlock_level_t unlock_level_change);
572575
bool unlock_gas_defence();
573-
bool is_gas_defence_unlocked() const;
576+
[[nodiscard]] bool is_gas_defence_unlocked() const;
574577

575578
bool modify_unit_variant_unlock(unit_variant_t unit_variant, technology_unlock_level_t unlock_level_change);
576579
bool unlock_unit_variant(unit_variant_t unit_variant);
577-
unit_variant_t get_max_unlocked_unit_variant() const;
580+
[[nodiscard]] unit_variant_t get_max_unlocked_unit_variant() const;
578581

579582
bool modify_technology_unlock(
580583
Technology const& technology, technology_unlock_level_t unlock_level_change
@@ -583,7 +586,7 @@ namespace OpenVic {
583586
Technology const& technology, technology_unlock_level_t unlock_level
584587
);
585588
bool unlock_technology(Technology const& technology);
586-
bool is_technology_unlocked(Technology const& technology) const;
589+
[[nodiscard]] bool is_technology_unlocked(Technology const& technology) const;
587590

588591
bool modify_invention_unlock(
589592
Invention const& invention, technology_unlock_level_t unlock_level_change
@@ -592,15 +595,15 @@ namespace OpenVic {
592595
Invention const& invention, technology_unlock_level_t unlock_level
593596
);
594597
bool unlock_invention(Invention const& invention);
595-
bool is_invention_unlocked(Invention const& invention) const;
598+
[[nodiscard]] bool is_invention_unlocked(Invention const& invention) const;
596599

597-
bool is_primary_culture(Culture const& culture) const;
600+
[[nodiscard]] bool is_primary_culture(Culture const& culture) const;
598601
// This only checks the accepted cultures list, ignoring the primary culture.
599-
bool is_accepted_culture(Culture const& culture) const;
600-
bool is_primary_or_accepted_culture(Culture const& culture) const;
602+
[[nodiscard]] bool is_accepted_culture(Culture const& culture) const;
603+
[[nodiscard]] bool is_primary_or_accepted_culture(Culture const& culture) const;
601604

602-
fixed_point_t calculate_research_cost(Technology const& technology) const;
603-
bool can_research_tech(Technology const& technology, const Date today) const;
605+
[[nodiscard]] fixed_point_t calculate_research_cost(Technology const& technology) const;
606+
[[nodiscard]] bool can_research_tech(Technology const& technology, const Date today) const;
604607
void start_research(Technology const& technology, const Date today);
605608

606609
// Sets the investment of each country in the map (rather than adding to them), leaving the rest unchanged.

src/openvic-simulation/economy/BuildingInstance.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,31 @@ BuildingInstance::BuildingInstance(BuildingType const& new_building_type, buildi
1010
level { new_level } {}
1111

1212
bool BuildingInstance::_can_expand() const {
13-
return level < building_type.get_max_level();
13+
return level < building_type.max_level;
1414
}
1515

16-
bool BuildingInstance::expand() {
17-
if (expansion_state == ExpansionState::CanExpand) {
18-
expansion_state = ExpansionState::Preparing;
19-
expansion_progress = 0;
20-
return true;
16+
bool BuildingInstance::expand(
17+
ModifierEffectCache const& modifier_effect_cache,
18+
CountryInstance& actor,
19+
ProvinceInstance const& location
20+
) {
21+
if (expansion_state != ExpansionState::CanExpand) {
22+
return false;
2123
}
22-
return false;
24+
25+
if (!building_type.can_be_build(
26+
modifier_effect_cache,
27+
level+1,
28+
actor,
29+
location
30+
)) {
31+
return false;
32+
}
33+
34+
//TODO add construction costs to actor
35+
expansion_state = ExpansionState::Preparing;
36+
expansion_progress = 0;
37+
return true;
2338
}
2439

2540
/* REQUIREMENTS:
@@ -29,7 +44,7 @@ void BuildingInstance::update_gamestate(Date today) {
2944
switch (expansion_state) {
3045
case ExpansionState::Preparing:
3146
start_date = today;
32-
end_date = start_date + building_type.get_build_time();
47+
end_date = start_date + building_type.build_time;
3348
break;
3449
case ExpansionState::Expanding:
3550
expansion_progress = fixed_point_t { static_cast<int32_t>((today - start_date).to_int()) }
@@ -50,3 +65,23 @@ void BuildingInstance::tick(Date today) {
5065
}
5166
}
5267
}
68+
69+
void BuildingInstance::set_level(const building_level_t new_level) {
70+
if (new_level == level) {
71+
return;
72+
}
73+
74+
if (new_level < level) {
75+
if (new_level < building_level_t(0)) {
76+
spdlog::error_s("Cannot set building level to {}, the minimum is 0.", new_level);
77+
level = building_level_t(0);
78+
} else {
79+
level = new_level;
80+
}
81+
} else if (new_level > building_type.max_level) {
82+
spdlog::error_s("Cannot set building level to {}, the maximum is {}.", new_level, building_type.max_level);
83+
level = building_type.max_level;
84+
} else {
85+
level = new_level;
86+
}
87+
}

0 commit comments

Comments
 (0)