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 16b480f
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 provinces which aren't state capitals, or don't have have a national focus applied, this will be [code]0[/code].
</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 the province does not have an RGO, 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 16b480f

Please sign in to comment.