Skip to content

Commit

Permalink
Add map projections
Browse files Browse the repository at this point in the history
  • Loading branch information
Nemrav committed Jan 16, 2025
1 parent 1852a5f commit f1c71cc
Show file tree
Hide file tree
Showing 10 changed files with 635 additions and 22 deletions.
35 changes: 35 additions & 0 deletions extension/doc_classes/MapItemSingleton.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,78 @@
<brief_description>
</brief_description>
<description>
This singleton provides methods of optaining [code]billboard[/code] and [code]projection[/code] type graphics objects. It also provides methods for getting the proper location of these objects on the map.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_billboards" qualifiers="const">
<return type="Dictionary[]" />
<description>
Returns an array of Dictionnaries. Each dictionnary contains the keys [code]name[/code] (String), [code]texture[/code] (String), [code]scale[/code] (float), [code]noOfFrames[/code] (int) used to make a billboard object. [code]texture[/code] is a [code]String[/code] path to the billboard texture. [code]noOfFrames[/code] is a [code]float[/code] scaling factor. [code]noOfFrames[/code] is an [code]int[/code] specifying how many icons are in the texture image.
</description>
</method>
<method name="get_capital_positions" qualifiers="const">
<return type="PackedVector2Array" />
<description>
Returns an array of the positions of country capital billboards for all existing countries. The capital billboard position is the [code]city[/code] property of a province which is a capital in the game defines.
</description>
</method>
<method name="get_clicked_port_province_index" qualifiers="const">
<return type="int" />
<param index="0" name="position" type="Vector2" />
<description>
Searches the mouse map coordinate for any port within a radius. Returns the province index of a found port, or [code]0[/code] if no port was found within the radius of the click.
</description>
</method>
<method name="get_crime_icons" qualifiers="const">
<return type="PackedByteArray" />
<description>
Returns an array of icon indices to use on the crimes texture to get the appropriate crime icons for every land province. An index of [code]0[/code] indicates there is no crime for that province.
</description>
</method>
<method name="get_max_capital_count" qualifiers="const">
<return type="int" />
<description>
Returns the size of the number of defined countries. This is the maximum possible number of capital billboards the game could have to display.
</description>
</method>
<method name="get_national_focus_icons" qualifiers="const">
<return type="PackedByteArray" />
<description>
TODO: WIP Function awaiting implementation of national focuses. Returns an array of icon indices used with the national focus icons texture for every province. For state capitals with a national focus applied, this will be a number [code]>= 1[/code], otherwise it will be 0.
</description>
</method>
<method name="get_port_position_by_province_index" qualifiers="const">
<return type="Vector2" />
<param index="0" name="index" type="int" />
<description>
Given a province [param]index[/param], returns the position of the province's port. Emits an error and returns [code]0,0[/code] if the province does not have a port.
</description>
</method>
<method name="get_projections" qualifiers="const">
<return type="Dictionary[]" />
<description>
Returns an array of Dictionnaries. Each dictionnary contains the keys [code]name[/code] (String), [code]texture[/code] (String), [code]size[/code] (float), [code]spin[/code] (float), [code]expanding[/code] (float), [code]duration[/code] (float), [code]additative[/code] (bool).
</description>
</method>
<method name="get_province_positions" qualifiers="const">
<return type="PackedVector2Array" />
<description>
Returns an array of billboard positions for every land province. This corresponds to a province's [code]city[/code] define.
</description>
</method>
<method name="get_rgo_icons" qualifiers="const">
<return type="PackedByteArray" />
<description>
Returns an array of icon indices used with the trade goods (RGO) icons texture for every land province. If the province has an RGO this will be [code]>= 1[/code], otherwise it will be 0.
</description>
</method>
<method name="get_unit_position_by_province_index" qualifiers="const">
<return type="Vector2" />
<param index="0" name="index" type="int" />
<description>
Given a province [param]index[/param], returns the province's unit position.
</description>
</method>
</methods>
Expand Down
150 changes: 135 additions & 15 deletions extension/src/openvic-extension/singletons/MapItemSingleton.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
#include "MapItemSingleton.hpp"
#include <string_view>

#include "godot_cpp/core/error_macros.hpp"
#include "godot_cpp/variant/packed_int32_array.hpp"
#include "godot_cpp/variant/packed_vector2_array.hpp"
#include "godot_cpp/variant/typed_array.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "godot_cpp/variant/vector2.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
#include "openvic-extension/utility/ClassBindings.hpp"
#include "openvic-extension/utility/Utilities.hpp"
#include "openvic-simulation/DefinitionManager.hpp"
#include "openvic-simulation/country/CountryDefinition.hpp"
#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/DefinitionManager.hpp"
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/interface/GFXObject.hpp"
#include "openvic-simulation/map/ProvinceDefinition.hpp"
#include "openvic-simulation/map/ProvinceInstance.hpp"
Expand All @@ -29,6 +30,11 @@ void MapItemSingleton::_bind_methods() {
OV_BIND_METHOD(MapItemSingleton::get_crime_icons);
OV_BIND_METHOD(MapItemSingleton::get_rgo_icons);
OV_BIND_METHOD(MapItemSingleton::get_national_focus_icons);
OV_BIND_METHOD(MapItemSingleton::get_projections);
OV_BIND_METHOD(MapItemSingleton::get_unit_position_by_province_index,{"index"});
OV_BIND_METHOD(MapItemSingleton::get_port_position_by_province_index,{"index"});
OV_BIND_METHOD(MapItemSingleton::get_clicked_port_province_index, {"position"});

}

MapItemSingleton* MapItemSingleton::get_singleton() {
Expand Down Expand Up @@ -63,27 +69,21 @@ GFX::Billboard const* MapItemSingleton::get_billboard(std::string_view name, boo
}

// repackage the billboard object into a godot dictionnary for the Billboard manager to work with
bool MapItemSingleton::add_billboard_dict(std::string_view name, TypedArray<Dictionary>& billboard_dict_array) const {
void MapItemSingleton::add_billboard_dict(GFX::Billboard const& billboard, TypedArray<Dictionary>& billboard_dict_array) const {

static const StringName name_key = "name";
static const StringName texture_key = "texture";
static const StringName scale_key = "scale";
static const StringName noOfFrames_key = "noFrames";

GFX::Billboard const* billboard = get_billboard(name, false);

ERR_FAIL_NULL_V_MSG(billboard, false, vformat("Failed to find billboard \"%s\"", Utilities::std_to_godot_string(name)));

Dictionary dict;

dict[name_key] = Utilities::std_to_godot_string(billboard->get_name());
dict[texture_key] = Utilities::std_to_godot_string(billboard->get_texture_file());
dict[scale_key] = billboard->get_scale().to_float();
dict[noOfFrames_key] = billboard->get_no_of_frames();
dict[name_key] = Utilities::std_to_godot_string(billboard.get_name());
dict[texture_key] = Utilities::std_to_godot_string(billboard.get_texture_file());
dict[scale_key] = billboard.get_scale().to_float();
dict[noOfFrames_key] = billboard.get_no_of_frames();

billboard_dict_array.push_back(dict);

return true;
}

//get an array of all the billboard dictionnaries
Expand All @@ -94,8 +94,64 @@ TypedArray<Dictionary> MapItemSingleton::get_billboards() const {
TypedArray<Dictionary> ret;

for (std::unique_ptr<GFX::Object> const& obj : game_singleton->get_definition_manager().get_ui_manager().get_objects()) {
if (obj->is_type<GFX::Billboard>()) {
add_billboard_dict(obj->get_name(), ret);
GFX::Billboard const* billboard = obj->cast_to<GFX::Billboard>();
if (billboard != nullptr) {
add_billboard_dict(*billboard, ret);
}
}

return ret;
}


GFX::Projection const* MapItemSingleton::get_projection(std::string_view name, bool error_on_fail) const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, nullptr);

GFX::Projection const* projection =
game_singleton->get_definition_manager().get_ui_manager().get_cast_object_by_identifier<GFX::Projection>(name);

if (error_on_fail) {
ERR_FAIL_NULL_V_MSG(
projection, nullptr, vformat("Failed to find projection \"%s\"", Utilities::std_to_godot_string(name))
);
}

return projection;
}

void MapItemSingleton::add_projection_dict(GFX::Projection const& projection, TypedArray<Dictionary>& projection_dict_array) const {
static const StringName name_key = "name";
static const StringName texture_key = "texture";
static const StringName size_key = "size";
static const StringName spin_key = "spin";
static const StringName expanding_key = "expanding";
static const StringName duration_key = "duration";
static const StringName additative_key = "additative";

Dictionary dict;

dict[name_key] = Utilities::std_to_godot_string(projection.get_name());
dict[texture_key] = Utilities::std_to_godot_string(projection.get_texture_file());
dict[size_key] = projection.get_size().to_float();
dict[spin_key] = projection.get_spin().to_float();
dict[expanding_key] = projection.get_expanding().to_float();
dict[duration_key] = projection.get_duration().to_float();
dict[additative_key] = projection.get_additative();

projection_dict_array.push_back(dict);
}

TypedArray<Dictionary> MapItemSingleton::get_projections() const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, {});

TypedArray<Dictionary> ret;

for (std::unique_ptr<GFX::Object> const& obj : game_singleton->get_definition_manager().get_ui_manager().get_objects()) {
GFX::Projection const* projection = obj->cast_to<GFX::Projection>();
if (projection != nullptr) {
add_projection_dict(*projection, ret);
}
}

Expand Down Expand Up @@ -260,3 +316,67 @@ PackedByteArray MapItemSingleton::get_national_focus_icons() const {

return icons;
}


Vector2 MapItemSingleton::get_unit_position_by_province_index(int32_t province_index) const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, {});

ProvinceDefinition const* province = game_singleton->get_definition_manager().get_map_definition()
.get_province_definition_by_index(province_index);
ERR_FAIL_NULL_V_MSG(province, {}, vformat("Cannot get unit position - invalid province index: %d", province_index));

return Utilities::to_godot_fvec2(province->get_unit_position())
/ GameSingleton::get_singleton()->get_map_dims();
}

Vector2 MapItemSingleton::get_port_position_by_province_index(int32_t province_index) const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, {});

ProvinceDefinition const* province = game_singleton->get_definition_manager().get_map_definition()
.get_province_definition_by_index(province_index);
ERR_FAIL_NULL_V_MSG(province, {}, vformat("Cannot get port position - invalid province index: %d", province_index));
ERR_FAIL_COND_V_MSG(!province->has_port(), {},vformat("Cannot get port position - invalid province index: %d", province_index) );

BuildingType const* port_building_type = game_singleton->get_definition_manager().get_economy_manager().get_building_type_manager().get_port_building_type();
fvec2_t const* port_position = province->get_building_position(port_building_type);

return Utilities::to_godot_fvec2(*port_position) / GameSingleton::get_singleton()->get_map_dims();
}

const static float port_radius = 0.0006; //how close we have to click for a detection

//Searches provinces near the one clicked and finds
int32_t MapItemSingleton::get_clicked_port_province_index(Vector2 click_position) const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, {});

int32_t initial_province_index = game_singleton->get_province_index_from_uv_coords(click_position);

//now get all the provinces around this one
ProvinceDefinition const* province = game_singleton->get_definition_manager().get_map_definition()
.get_province_definition_by_index(initial_province_index);
ERR_FAIL_NULL_V_MSG(province, {}, vformat("Cannot get port position - invalid province index: %d", initial_province_index));

BuildingType const* port_building_type = game_singleton->get_definition_manager().get_economy_manager().get_building_type_manager().get_port_building_type();

if(province->has_port()){
Vector2 port_position = Utilities::to_godot_fvec2(*province->get_building_position(port_building_type)) / GameSingleton::get_singleton()->get_map_dims();
if(click_position.distance_to(port_position) <= port_radius){
return province->get_index();
}
}
else if(province->is_water()){
for(ProvinceDefinition::adjacency_t const& adjacency : province->get_adjacencies()) {
ProvinceDefinition const* adjacent_province = adjacency.get_to();
if(!adjacent_province->has_port()) continue; // skip provinces without ports (ie. other water provinces)
Vector2 port_position = Utilities::to_godot_fvec2(*adjacent_province->get_building_position(port_building_type)) / GameSingleton::get_singleton()->get_map_dims();
if(click_position.distance_to(port_position) <= port_radius){
return adjacent_province->get_index();
}
}
}

return 0;
}
14 changes: 11 additions & 3 deletions extension/src/openvic-extension/singletons/MapItemSingleton.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
#include <openvic-simulation/interface/GFXObject.hpp>
#include <openvic-simulation/types/OrderedContainers.hpp>

//billboards, projections, and progress bar
//for now though, only billboards
//billboards, projections, and progress bar (no progress bar yet)

namespace OpenVic {
class MapItemSingleton : public godot::Object {
Expand All @@ -25,14 +24,23 @@ namespace OpenVic {

private:
GFX::Billboard const* get_billboard(std::string_view name, bool error_on_fail = true) const;
bool add_billboard_dict(std::string_view name, godot::TypedArray<godot::Dictionary>& billboard_dict_array) const;
void add_billboard_dict(GFX::Billboard const& billboard, godot::TypedArray<godot::Dictionary>& billboard_dict_array) const;
godot::TypedArray<godot::Dictionary> get_billboards() const;

GFX::Projection const* get_projection(std::string_view name, bool error_on_fail = true) const;
void add_projection_dict(GFX::Projection const& projection, godot::TypedArray<godot::Dictionary>& projection_dict_array) const;
godot::TypedArray<godot::Dictionary> get_projections() const;

godot::PackedVector2Array get_province_positions() const;
int32_t get_max_capital_count() const;
godot::PackedVector2Array get_capital_positions() const;

godot::PackedByteArray get_crime_icons() const;
godot::PackedByteArray get_rgo_icons() const;
godot::PackedByteArray get_national_focus_icons() const;

godot::Vector2 get_unit_position_by_province_index(int32_t province_index) const;
godot::Vector2 get_port_position_by_province_index(int32_t province_index) const;
int32_t get_clicked_port_province_index(godot::Vector2 click_position) const;
};
}
5 changes: 5 additions & 0 deletions game/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ menu_pause={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
select_add={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}

[internationalization]

Expand Down
Loading

0 comments on commit f1c71cc

Please sign in to comment.