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 e003b2f
Show file tree
Hide file tree
Showing 10 changed files with 611 additions and 22 deletions.
11 changes: 11 additions & 0 deletions extension/doc_classes/MapItemSingleton.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
<description>
</description>
</method>
<method name="get_projections" qualifiers="const">
<return type="Dictionary[]" />
<description>
</description>
</method>
<method name="get_province_positions" qualifiers="const">
<return type="PackedVector2Array" />
<description>
Expand All @@ -42,5 +47,11 @@
<description>
</description>
</method>
<method name="get_unit_position_by_province_index" qualifiers="const">
<return type="Vector2" />
<param index="0" name="index" type="int" />
<description>
</description>
</method>
</methods>
</class>
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
34 changes: 32 additions & 2 deletions game/src/Game/GameSession/MapView.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const _action_zoom_out : StringName = &"map_zoom_out"
const _action_drag : StringName = &"map_drag"
const _action_click : StringName = &"map_click"
const _action_right_click : StringName = &"map_right_click"
const _action_select_add : StringName = &"select_add"

@export var _camera : Camera3D

Expand Down Expand Up @@ -60,6 +61,11 @@ var _viewport_dims : Vector2 = Vector2(1, 1)

@export var _map_text : MapText

@export var validMoveMarkers : ValidMoveMarkers
@export var selectionMarkers : SelectionMarkers
var land_units_selected : Array = []
var naval_units_selected : Array = []

# ??? Strange Godot/GDExtension Bug ???
# Upon first opening a clone of this repo with the Godot Editor,
# if GameSingleton.get_province_index_image is called before MapMesh
Expand Down Expand Up @@ -201,6 +207,7 @@ func _input(event : InputEvent) -> void:
# * SS-31
# * SS-75
var _cardinal_movement_vector := Vector2.ZERO
var temp_id : int = 0
func _unhandled_input(event : InputEvent) -> void:
if event is InputEventMouseMotion:
_mouse_over_viewport = true
Expand All @@ -215,19 +222,42 @@ func _unhandled_input(event : InputEvent) -> void:
_action_south
) * _cardinal_move_speed

elif event.is_action_pressed(_action_select_add):
if _mouse_over_viewport:
if _map_mesh.is_valid_uv_coord(_mouse_pos_map):
GameSingleton.set_selected_province(GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map))
var province_index : int = GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map)

var port_province_index : int = MapItemSingleton.get_clicked_port_province_index(_mouse_pos_map)
if port_province_index != 0:
var port_pos : Vector2 = MapItemSingleton.get_port_position_by_province_index(port_province_index)
selectionMarkers.add_selection_marker(temp_id,_map_to_world_coords(port_pos))
else:
var unit_position : Vector2 = MapItemSingleton.get_unit_position_by_province_index(province_index)
selectionMarkers.add_selection_marker(temp_id,_map_to_world_coords(unit_position))
temp_id += 1

elif event.is_action_pressed(_action_click):
if _mouse_over_viewport:
# Check if the mouse is outside of bounds
if _map_mesh.is_valid_uv_coord(_mouse_pos_map):
GameSingleton.set_selected_province(GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map))
selectionMarkers.clear_selection_markers()
else:
print("Clicked outside the map!")
elif event.is_action_pressed(_action_right_click):
if _mouse_over_viewport:
if _map_mesh.is_valid_uv_coord(_mouse_pos_map):
var province_index : int = GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map)
var port_province_index : int = MapItemSingleton.get_clicked_port_province_index(_mouse_pos_map)
if port_province_index != 0:
var port_pos : Vector2 = MapItemSingleton.get_port_position_by_province_index(port_province_index)
validMoveMarkers.add_move_marker(_map_to_world_coords(port_pos), randi_range(0,1))
else:
var unit_position : Vector2 = MapItemSingleton.get_unit_position_by_province_index(province_index)
validMoveMarkers.add_move_marker(_map_to_world_coords(unit_position), randi_range(0,1))
# TODO - open diplomacy screen on province owner or viewed country if province has no owner
#Events.NationManagementScreens.open_nation_management_screen(NationManagement.Screen.DIPLOMACY)
GameSingleton.set_viewed_country_by_province_index(GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map))
GameSingleton.set_viewed_country_by_province_index(province_index)
else:
print("Right-clicked outside the map!")
elif event.is_action_pressed(_action_drag):
Expand Down
Loading

0 comments on commit e003b2f

Please sign in to comment.