aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/map/ProvinceDefinition.cpp
blob: bb8ad59608667ffe57fc20ee3a9dc8fc8bdbc7ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include "ProvinceDefinition.hpp"

#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/map/Map.hpp"

using namespace OpenVic;
using namespace OpenVic::NodeTools;

ProvinceDefinition::ProvinceDefinition(
   std::string_view new_identifier, colour_t new_colour, index_t new_index
) : HasIdentifierAndColour { new_identifier, new_colour, true }, index { new_index }, region { nullptr },
   climate { nullptr }, continent { nullptr }, on_map { false }, water { false }, coastal { false },
   port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, adjacencies {}, centre {},
   positions {} {
   assert(index != NULL_INDEX);
}

bool ProvinceDefinition::operator==(ProvinceDefinition const& other) const {
   return this == &other;
}

std::string ProvinceDefinition::to_string() const {
   std::stringstream stream;
   stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << get_colour() << ")";
   return stream.str();
}

bool ProvinceDefinition::load_positions(Map const& map, BuildingTypeManager const& building_type_manager, ast::NodeCPtr root) {
   const fixed_point_t map_height = map.get_height();

   const bool ret = expect_dictionary_keys(
      "text_position", ZERO_OR_ONE,
         expect_fvec2(flip_y_callback(assign_variable_callback(positions.text_position), map_height)),
      "text_rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_rotation)),
      "text_scale", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(positions.text_scale)),

      "unit", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.unit), map_height)),
      "town", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)),
      "city", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.city), map_height)),
      "factory", ZERO_OR_ONE, expect_fvec2(flip_y_callback(assign_variable_callback(positions.factory), map_height)),

      "building_construction", ZERO_OR_ONE,
         expect_fvec2(flip_y_callback(assign_variable_callback(positions.building_construction), map_height)),
      "military_construction", ZERO_OR_ONE,
         expect_fvec2(flip_y_callback(assign_variable_callback(positions.military_construction), map_height)),

      "building_position", ZERO_OR_ONE, building_type_manager.expect_building_type_dictionary_reserve_length(
         positions.building_position,
         [this, map_height](BuildingType const& type, ast::NodeCPtr value) -> bool {
            return expect_fvec2(flip_y_callback(map_callback(positions.building_position, &type), map_height))(value);
         }
      ),
      "building_rotation", ZERO_OR_ONE, building_type_manager.expect_building_type_decimal_map(
         move_variable_callback(positions.building_rotation), std::negate {}
      ),

      /* the below are esoteric clausewitz leftovers that either have no impact or whose functionality is lost to time */
      "spawn_railway_track", ZERO_OR_ONE, success_callback,
      "railroad_visibility", ZERO_OR_ONE, success_callback,
      "building_nudge", ZERO_OR_ONE, success_callback
   )(root);

   if (coastal) {
      fvec2_t const* port_position = get_building_position(building_type_manager.get_port_building_type());
      if (port_position != nullptr) {
         const fixed_point_t rotation = get_building_rotation(building_type_manager.get_port_building_type());

         /* At 0 rotation the port faces west, as rotation increases the port rotates anti-clockwise. */
         const fvec2_t port_dir { -rotation.cos(), rotation.sin() };
         const ivec2_t port_facing_position = static_cast<ivec2_t>(*port_position + port_dir / 4);

         ProvinceDefinition const* province = map.get_province_definition_at(port_facing_position);

         if (province != nullptr) {
            if (province->is_water() && is_adjacent_to(province)) {
               port = true;
               port_adjacent_province = province;
            } else {
               /*  Expected provinces with invalid ports: 39, 296, 1047, 1406, 2044 */
               Logger::warning(
                  "Invalid port for province ", get_identifier(), ": facing province ", province,
                  " which has: water = ", province->is_water(), ", adjacent = ", is_adjacent_to(province)
               );
            }
         } else {
            Logger::warning("Invalid port for province ", get_identifier(), ": facing null province!");
         }
      }
   }

   return ret;
}

fvec2_t ProvinceDefinition::get_text_position() const {
   return positions.text_position.value_or(centre);
}

fixed_point_t ProvinceDefinition::get_text_rotation() const {
   return positions.text_rotation.value_or(0);
}

fixed_point_t ProvinceDefinition::get_text_scale() const {
   return positions.text_scale.value_or(1);
}

fvec2_t const* ProvinceDefinition::get_building_position(BuildingType const* building_type) const {
   if (building_type != nullptr) {
      const decltype(positions.building_position)::const_iterator it = positions.building_position.find(building_type);

      if (it != positions.building_position.end()) {
         return &it->second;
      }
   }
   return nullptr;
}

fixed_point_t ProvinceDefinition::get_building_rotation(BuildingType const* building_type) const {
   if (building_type != nullptr) {
      const decltype(positions.building_rotation)::const_iterator it = positions.building_rotation.find(building_type);

      if (it != positions.building_rotation.end()) {
         return it->second;
      }
   }
   return 0;
}

ProvinceDefinition::adjacency_t::adjacency_t(
   ProvinceDefinition const* new_to, distance_t new_distance, type_t new_type, ProvinceDefinition const* new_through,
   data_t new_data
) : to { new_to }, distance { new_distance }, type { new_type }, through { new_through }, data { new_data } {}

std::string_view ProvinceDefinition::adjacency_t::get_type_name(type_t type) {
   switch (type) {
   case type_t::LAND: return "Land";
   case type_t::WATER: return "Water";
   case type_t::COASTAL: return "Coastal";
   case type_t::IMPASSABLE: return "Impassable";
   case type_t::STRAIT: return "Strait";
   case type_t::CANAL: return "Canal";
   default: return "Invalid Adjacency Type";
   }
}

ProvinceDefinition::adjacency_t const* ProvinceDefinition::get_adjacency_to(ProvinceDefinition const* province) const {
   const std::vector<adjacency_t>::const_iterator it = std::find_if(adjacencies.begin(), adjacencies.end(),
      [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; }
   );
   if (it != adjacencies.end()) {
      return &*it;
   } else {
      return nullptr;
   }
}

bool ProvinceDefinition::is_adjacent_to(ProvinceDefinition const* province) const {
   return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(),
      [province](adjacency_t const& adj) -> bool { return adj.get_to() == province; }
   );
}

std::vector<ProvinceDefinition::adjacency_t const*> ProvinceDefinition::get_adjacencies_going_through(
   ProvinceDefinition const* province
) const {
   std::vector<adjacency_t const*> ret;
   for (adjacency_t const& adj : adjacencies) {
      if (adj.get_through() == province) {
         ret.push_back(&adj);
      }
   }
   return ret;
}

bool ProvinceDefinition::has_adjacency_going_through(ProvinceDefinition const* province) const {
   return province != nullptr && std::any_of(adjacencies.begin(), adjacencies.end(),
      [province](adjacency_t const& adj) -> bool { return adj.get_through() == province; }
   );
}

fvec2_t ProvinceDefinition::get_unit_position() const {
   return positions.unit.value_or(centre);
}