Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions src/openvic-simulation/country/CountryInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "openvic-simulation/defines/EconomyDefines.hpp"
#include "openvic-simulation/defines/MilitaryDefines.hpp"
#include "openvic-simulation/diplomacy/CountryRelation.hpp"
#include "openvic-simulation/economy/BuildingLevel.hpp"
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/economy/GoodInstance.hpp"
#include "openvic-simulation/economy/production/ProductionType.hpp"
Expand Down Expand Up @@ -275,7 +276,7 @@ CountryInstance::CountryInstance(
update_parties_for_votes(new_country_definition);

for (BuildingType const& building_type : building_type_unlock_levels.get_keys()) {
if (building_type.is_default_enabled()) {
if (building_type.is_enabled_by_default) {
unlock_building_type(building_type);
}
}
Expand Down Expand Up @@ -335,6 +336,45 @@ bool CountryInstance::is_neighbour(CountryInstance const& country) const {
return neighbouring_countries.contains(&country);
}

bool CountryInstance::may_build_in(const BuildingRestrictionCategory restriction_category, ProvinceInstance const& location) const {
CountryInstance const* const owner_ptr = location.get_owner();

if (owner_ptr == nullptr) {
//Can't build in uncolonised provinces
return false;
}
CountryInstance const& owner = *owner_ptr;

if (owner == *this) {
switch(restriction_category) {
case BuildingRestrictionCategory::UNRESTRICTED:
return true;
case BuildingRestrictionCategory::INFRASTRUCTURE:
return rule_set.may_expand_infrastructure_domestically();
case BuildingRestrictionCategory::FACTORY:
return rule_set.may_build_factory_domestically();
}
}

if (is_at_war_with(owner)) {
//Not allowed to build in hostile lands.
return false;
}

if (!owner.rule_set.foreigners_may_invest()) {
return false;
}

switch(restriction_category) {
case BuildingRestrictionCategory::UNRESTRICTED:
return false; //For example you can't invest in foreign forts.
case BuildingRestrictionCategory::INFRASTRUCTURE:
return rule_set.may_invest_in_expanding_infrastructure_abroad();
case BuildingRestrictionCategory::FACTORY:
return rule_set.may_invest_in_building_factory_abroad();
}
}

CountryRelationManager::relation_value_type CountryInstance::get_relations_with(CountryInstance const& country) const {
return country_relations_manager.get_country_relation(this, &country);
}
Expand Down Expand Up @@ -870,12 +910,13 @@ bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const {
}

bool CountryInstance::modify_building_type_unlock(
BuildingType const& building_type, technology_unlock_level_t unlock_level_change
BuildingType const& building_type, technology_unlock_level_t tech_unlock_level_change
) {
technology_unlock_level_t& unlock_level = building_type_unlock_levels.at(building_type);
building_level_t& unlock_level = building_type_unlock_levels.at(building_type);
building_level_t unlock_level_change = building_level_t(type_safe::get(tech_unlock_level_change));

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

unlock_level += unlock_level_change;

if (building_type.get_production_type() != nullptr) {
good_instance_manager.enable_good(building_type.get_production_type()->output_good);
if (building_type.production_type != nullptr) {
good_instance_manager.enable_good(building_type.production_type->output_good);
}

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

building_level_t const& CountryInstance::get_building_type_unlock_levels(BuildingType const& building_type) const {
return building_type_unlock_levels.at(building_type);
}

bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const {
return building_type_unlock_levels.at(building_type) > 0;
return building_type_unlock_levels.at(building_type) > building_level_t(0);
}

bool CountryInstance::modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change) {
Expand Down
87 changes: 45 additions & 42 deletions src/openvic-simulation/country/CountryInstance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <fmt/base.h>

#include "openvic-simulation/diplomacy/CountryRelation.hpp"
#include "openvic-simulation/economy/BuildingLevel.hpp"
#include "openvic-simulation/economy/BuildingRestrictionCategory.hpp"
#include "openvic-simulation/military/CombatWidth.hpp"
#include "openvic-simulation/military/UnitBranchedGetterMacro.hpp"
#include "openvic-simulation/modifier/ModifierSum.hpp"
Expand Down Expand Up @@ -155,7 +157,7 @@ namespace OpenVic {
memory::vector<std::pair<CountryInstance const*, fixed_point_t>> SPAN_PROPERTY(industrial_power_from_investments);
size_t PROPERTY(industrial_rank, 0);
fixed_point_map_t<CountryInstance const*> PROPERTY(foreign_investments);
OV_IFLATMAP_PROPERTY(BuildingType, technology_unlock_level_t, building_type_unlock_levels);
OV_IFLATMAP_PROPERTY(BuildingType, building_level_t, building_type_unlock_levels);
// TODO - total amount of each good produced

/* Budget */
Expand Down Expand Up @@ -410,57 +412,58 @@ namespace OpenVic {
OV_UNIT_BRANCHED_GETTER(get_leaders, generals, admirals);
OV_UNIT_BRANCHED_GETTER_CONST(get_leaders, generals, admirals);

inline size_t get_general_count() const {
[[nodiscard]] inline size_t get_general_count() const {
return generals.size();
}
inline bool has_generals() const {
[[nodiscard]] inline bool has_generals() const {
return !generals.empty();
}
inline size_t get_admiral_count() const {
[[nodiscard]] inline size_t get_admiral_count() const {
return admirals.size();
}
inline bool has_admirals() const {
[[nodiscard]] inline bool has_admirals() const {
return !admirals.empty();
}
inline size_t get_leader_count() const {
[[nodiscard]] inline size_t get_leader_count() const {
return get_general_count() + get_admiral_count();
}
inline bool has_leaders() const {
[[nodiscard]] inline bool has_leaders() const {
return has_generals() || has_admirals();
}
inline size_t get_army_count() const {
[[nodiscard]] inline size_t get_army_count() const {
return armies.size();
}
inline bool has_armies() const {
[[nodiscard]] inline bool has_armies() const {
return !armies.empty();
}
inline size_t get_navy_count() const {
[[nodiscard]] inline size_t get_navy_count() const {
return navies.size();
}
inline bool has_navies() const {
[[nodiscard]] inline bool has_navies() const {
return !navies.empty();
}

std::string_view get_identifier() const;
[[nodiscard]] std::string_view get_identifier() const;

bool exists() const;
bool is_rebel_country() const;
bool is_civilised() const;
bool can_colonise() const;
bool is_great_power() const;
bool is_secondary_power() const;
bool is_at_war() const;
bool is_neighbour(CountryInstance const& country) const;
[[nodiscard]] bool exists() const;
[[nodiscard]] bool is_rebel_country() const;
[[nodiscard]] bool is_civilised() const;
[[nodiscard]] bool can_colonise() const;
[[nodiscard]] bool is_great_power() const;
[[nodiscard]] bool is_secondary_power() const;
[[nodiscard]] bool is_at_war() const;
[[nodiscard]] bool is_neighbour(CountryInstance const& country) const;
[[nodiscard]] bool may_build_in(const BuildingRestrictionCategory restriction_category, ProvinceInstance const& location) const;

// Double-sided diplomacy functions

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

bool has_alliance_with(CountryInstance const& country) const;
[[nodiscard]] bool has_alliance_with(CountryInstance const& country) const;
void set_alliance_with(CountryInstance& country, bool alliance = true);

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

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

bool is_sending_war_subsidy_to(CountryInstance const& country) const;
[[nodiscard]] bool is_sending_war_subsidy_to(CountryInstance const& country) const;
void set_sending_war_subsidy_to(CountryInstance& country, bool sending = true);

bool is_commanding_units(CountryInstance const& country) const;
[[nodiscard]] bool is_commanding_units(CountryInstance const& country) const;
void set_commanding_units(CountryInstance& country, bool commanding = true);

bool has_vision_of(CountryInstance const& country) const;
[[nodiscard]] bool has_vision_of(CountryInstance const& country) const;
void set_has_vision_of(CountryInstance& country, bool vision = true);

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

bool can_army_units_enter(CountryInstance const& country) const;
bool can_navy_units_enter(CountryInstance const& country) const;
[[nodiscard]] bool can_army_units_enter(CountryInstance const& country) const;
[[nodiscard]] bool can_navy_units_enter(CountryInstance const& country) const;

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

bool has_leader_with_name(std::string_view name) const;
[[nodiscard]] bool has_leader_with_name(std::string_view name) const;

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

bool modify_unit_type_unlock(UnitType const& unit_type, technology_unlock_level_t unlock_level_change);
bool unlock_unit_type(UnitType const& unit_type);
bool is_unit_type_unlocked(UnitType const& unit_type) const;
[[nodiscard]] bool is_unit_type_unlocked(UnitType const& unit_type) const;

bool modify_building_type_unlock(
BuildingType const& building_type, technology_unlock_level_t unlock_level_change
);
bool unlock_building_type(BuildingType const& building_type);
bool is_building_type_unlocked(BuildingType const& building_type) const;
[[nodiscard]] bool is_building_type_unlocked(BuildingType const& building_type) const;

bool modify_crime_unlock(Crime const& crime, technology_unlock_level_t unlock_level_change);
bool unlock_crime(Crime const& crime);
bool is_crime_unlocked(Crime const& crime) const;
[[nodiscard]] bool is_crime_unlocked(Crime const& crime) const;

bool modify_gas_attack_unlock(technology_unlock_level_t unlock_level_change);
bool unlock_gas_attack();
bool is_gas_attack_unlocked() const;
[[nodiscard]] bool is_gas_attack_unlocked() const;

bool modify_gas_defence_unlock(technology_unlock_level_t unlock_level_change);
bool unlock_gas_defence();
bool is_gas_defence_unlocked() const;
[[nodiscard]] bool is_gas_defence_unlocked() const;

bool modify_unit_variant_unlock(unit_variant_t unit_variant, technology_unlock_level_t unlock_level_change);
bool unlock_unit_variant(unit_variant_t unit_variant);
unit_variant_t get_max_unlocked_unit_variant() const;
[[nodiscard]] unit_variant_t get_max_unlocked_unit_variant() const;

bool modify_technology_unlock(
Technology const& technology, technology_unlock_level_t unlock_level_change
Expand All @@ -583,7 +586,7 @@ namespace OpenVic {
Technology const& technology, technology_unlock_level_t unlock_level
);
bool unlock_technology(Technology const& technology);
bool is_technology_unlocked(Technology const& technology) const;
[[nodiscard]] bool is_technology_unlocked(Technology const& technology) const;

bool modify_invention_unlock(
Invention const& invention, technology_unlock_level_t unlock_level_change
Expand All @@ -592,15 +595,15 @@ namespace OpenVic {
Invention const& invention, technology_unlock_level_t unlock_level
);
bool unlock_invention(Invention const& invention);
bool is_invention_unlocked(Invention const& invention) const;
[[nodiscard]] bool is_invention_unlocked(Invention const& invention) const;

bool is_primary_culture(Culture const& culture) const;
[[nodiscard]] bool is_primary_culture(Culture const& culture) const;
// This only checks the accepted cultures list, ignoring the primary culture.
bool is_accepted_culture(Culture const& culture) const;
bool is_primary_or_accepted_culture(Culture const& culture) const;
[[nodiscard]] bool is_accepted_culture(Culture const& culture) const;
[[nodiscard]] bool is_primary_or_accepted_culture(Culture const& culture) const;

fixed_point_t calculate_research_cost(Technology const& technology) const;
bool can_research_tech(Technology const& technology, const Date today) const;
[[nodiscard]] fixed_point_t calculate_research_cost(Technology const& technology) const;
[[nodiscard]] bool can_research_tech(Technology const& technology, const Date today) const;
void start_research(Technology const& technology, const Date today);

// Sets the investment of each country in the map (rather than adding to them), leaving the rest unchanged.
Expand Down
51 changes: 43 additions & 8 deletions src/openvic-simulation/economy/BuildingInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,31 @@ BuildingInstance::BuildingInstance(BuildingType const& new_building_type, buildi
level { new_level } {}

bool BuildingInstance::_can_expand() const {
return level < building_type.get_max_level();
return level < building_type.max_level;
}

bool BuildingInstance::expand() {
if (expansion_state == ExpansionState::CanExpand) {
expansion_state = ExpansionState::Preparing;
expansion_progress = 0;
return true;
bool BuildingInstance::expand(
ModifierEffectCache const& modifier_effect_cache,
CountryInstance& actor,
ProvinceInstance const& location
) {
if (expansion_state != ExpansionState::CanExpand) {
return false;
}
return false;

if (!building_type.can_be_built_in(
modifier_effect_cache,
level+1,
actor,
location
)) {
return false;
}

//TODO add construction costs to actor
expansion_state = ExpansionState::Preparing;
expansion_progress = 0;
return true;
}

/* REQUIREMENTS:
Expand All @@ -29,7 +44,7 @@ void BuildingInstance::update_gamestate(Date today) {
switch (expansion_state) {
case ExpansionState::Preparing:
start_date = today;
end_date = start_date + building_type.get_build_time();
end_date = start_date + building_type.build_time;
break;
case ExpansionState::Expanding:
expansion_progress = fixed_point_t { static_cast<int32_t>((today - start_date).to_int()) }
Expand All @@ -50,3 +65,23 @@ void BuildingInstance::tick(Date today) {
}
}
}

void BuildingInstance::set_level(const building_level_t new_level) {
if (new_level == level) {
return;
}

if (new_level < level) {
if (new_level < building_level_t(0)) {
spdlog::error_s("Cannot set building level to {}, the minimum is 0.", new_level);
level = building_level_t(0);
} else {
level = new_level;
}
} else if (new_level > building_type.max_level) {
spdlog::error_s("Cannot set building level to {}, the maximum is {}.", new_level, building_type.max_level);
level = building_type.max_level;
} else {
level = new_level;
}
}
Loading