aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format17
-rw-r--r--.gitmodules3
-rw-r--r--README.md15
-rw-r--r--SConstruct11
m---------extension/deps/openvic-dataloader0
m---------extension/deps/openvic-simulation0
-rw-r--r--extension/src/LoadGameCompatibility.cpp153
-rw-r--r--extension/src/LoadGameOpenVic.cpp469
-rw-r--r--extension/src/openvic-extension/Checksum.hpp (renamed from extension/src/Checksum.hpp)0
-rw-r--r--extension/src/openvic-extension/GameSingleton.cpp (renamed from extension/src/GameSingleton.cpp)123
-rw-r--r--extension/src/openvic-extension/GameSingleton.hpp (renamed from extension/src/GameSingleton.hpp)44
-rw-r--r--extension/src/openvic-extension/LoadGameCompatibility.cpp110
-rw-r--r--extension/src/openvic-extension/LoadGameOpenVic.cpp132
-rw-r--r--extension/src/openvic-extension/LoadLocalisation.cpp (renamed from extension/src/LoadLocalisation.cpp)0
-rw-r--r--extension/src/openvic-extension/LoadLocalisation.hpp (renamed from extension/src/LoadLocalisation.hpp)0
-rw-r--r--extension/src/openvic-extension/MapMesh.cpp (renamed from extension/src/MapMesh.cpp)0
-rw-r--r--extension/src/openvic-extension/MapMesh.hpp (renamed from extension/src/MapMesh.hpp)0
-rw-r--r--extension/src/openvic-extension/Utilities.cpp (renamed from extension/src/Utilities.cpp)12
-rw-r--r--extension/src/openvic-extension/Utilities.hpp (renamed from extension/src/Utilities.hpp)4
-rw-r--r--extension/src/openvic-extension/register_types.cpp (renamed from extension/src/register_types.cpp)10
-rw-r--r--extension/src/openvic-extension/register_types.hpp (renamed from extension/src/register_types.h)0
-rw-r--r--game/localisation/en_GB/mapmodes.csv1
-rw-r--r--game/project.godot13
-rw-r--r--game/src/Game/Autoload/Argument/ArgumentParser.gd4
-rw-r--r--game/src/Game/Autoload/GameLoader.gd12
-rw-r--r--game/src/Game/Autoload/WindowOverride.gd27
-rw-r--r--game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd4
-rw-r--r--game/src/Game/GameSession/ProvinceOverviewPanel/ProvinceOverviewPanel.tscn3
-rw-r--r--game/src/Game/GameStart.gd56
-rw-r--r--game/src/Game/LoadingScreen.tscn1
30 files changed, 394 insertions, 830 deletions
diff --git a/.clang-format b/.clang-format
index bfa989e..e94fe0a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -24,7 +24,7 @@ SpaceBeforeAssignmentOperators: true
SpaceAfterTemplateKeyword: false
SpaceAfterLogicalNot: false
PointerAlignment: Left
-PackConstructorInitializers: CurrentLine
+PackConstructorInitializers: BinPack
NamespaceIndentation: All
LambdaBodyIndentation: Signature
IndentExternBlock: Indent
@@ -43,8 +43,11 @@ AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortEnumsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AlignTrailingComments: true
-AlignEscapedNewlines: Left
-AlignAfterOpenBracket: DontAlign
+AlignEscapedNewlines: DontAlign
+AlignAfterOpenBracket: BlockIndent
+BinPackArguments: true
+BinPackParameters: true
+IndentRequiresClause: false
AccessModifierOffset: -4
IncludeCategories:
- Regex: <[[:alnum:]_]+>
@@ -53,7 +56,11 @@ IncludeCategories:
Priority: 2
- Regex: ^<godot_cpp/
Priority: 3
- - Regex: ^"openvic/
+ - Regex: ^<openvic-dataloader/
Priority: 4
- - Regex: .*
+ - Regex: ^<openvic-simulation/
Priority: 5
+ - Regex: ^"openvic-extension/
+ Priority: 6
+ - Regex: .*
+ Priority: 7
diff --git a/.gitmodules b/.gitmodules
index 5e462da..26eca85 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,6 +4,3 @@
[submodule "extension/deps/openvic-simulation"]
path = extension/deps/openvic-simulation
url = https://github.com/OpenVicProject/OpenVic-Simulation
-[submodule "extension/deps/openvic-dataloader"]
- path = extension/deps/openvic-dataloader
- url = https://github.com/OpenVicProject/OpenVic-Dataloader
diff --git a/README.md b/README.md
index c0299e2..2f93ebe 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,8 @@ For detailed instructions, view the Contributor Quickstart Guide [here](docs/con
* [scons](https://scons.org/)
## Repo Setup
-1. Clone the OpenVic Repo to a suitable folder using the git command "git clone https://github.com/OpenVicProject/OpenVic.git"
-2. Update the submodules by executing the git command "git submodule update --init --recursive"
+1. Clone the OpenVic Repo to a suitable folder using the git command `git clone https://github.com/OpenVicProject/OpenVic.git`
+2. Update the submodules by executing the git command `git submodule update --init --recursive`
Note that using a zip download instead of cloning means a lot of work in manually managing submodules individually. It is strongly recommended to use git to obtain the source code.
@@ -24,6 +24,17 @@ Note that using a zip download instead of cloning means a lot of work in manuall
5. Press "Import & Edit", wait for the Editor to finish re-importing assets, and then close the Editor ***without saving*** and reopen the project.
6. Once loaded, click the play button at the top right, and you should see and hear the game application open on the main menu.
+## Build/Run Instructions for Archlinux (using yay)
+1. Install [Godot 4.1.1](https://archlinux.org/packages/extra/x86_64/godot/) with `yay -S Godot` and [scons](https://archlinux.org/packages/extra/any/scons/) with ` yay -S scons`.
+2. Clone the OpenVic Repo using the git command `git clone https://github.com/OpenVicProject/OpenVic.git`.
+3. CD into the game directory with `cd ./OpenVic`.
+4. Update the submodules by executing the git command `sudo git submodule update --init --recursive`.
+5. While still in the game directory, run `scons`.
+6. Now launch Godot 4, click import and navigate to `OpenVic` then to `game`.
+7. Click `project.godot`.
+5. Press "Import & Edit", wait for the Editor to finish re-importing assets, and then close the Editor ***without saving*** and reopen the project.
+6. Once loaded, click the play button at the top right, and you should see and hear the game application open on the main menu.
+
## Project Export
1. Build the extension with `scons` or `scons target=template_debug`. (or `scons target=template_release` for release)
2. Open `game/project.godot` with Godot 4.
diff --git a/SConstruct b/SConstruct
index eefd99d..2d34e01 100644
--- a/SConstruct
+++ b/SConstruct
@@ -2,7 +2,6 @@
import os
import sys
from glob import glob
-from pathlib import Path
# Local
from scripts.build.option_handler import OptionsClass
@@ -60,9 +59,15 @@ if env["compiledb"]:
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
+ovsim_env = SConscript("extension/deps/openvic-simulation/SConstruct")
+
+env.Append(LIBPATH=ovsim_env.openvic_simulation["LIBPATH"])
+env.Append(LIBS=ovsim_env.openvic_simulation["LIBS"])
+env.Append(CPPPATH=ovsim_env.openvic_simulation["INCPATH"])
+
# tweak this if you want to use different folders, or more folders, to store your source code in.
-paths = ["extension/src/", "extension/deps/openvic-simulation/src/"]
-env.Append(CPPPATH=paths)
+paths = ["extension/src/"]
+env.Append(CPPPATH=[[env.Dir(p) for p in paths]])
sources = GlobRecursive("*.cpp", paths)
env.extension_sources = sources
diff --git a/extension/deps/openvic-dataloader b/extension/deps/openvic-dataloader
deleted file mode 160000
-Subproject 65443efcc2f4c7d687b2bd9c631f6bb426688bb
diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation
-Subproject 383ef70bea656a77e8b7c6843fd4a79705ecde4
+Subproject 6278a35f4704574933464700026d8deb997da5c
diff --git a/extension/src/LoadGameCompatibility.cpp b/extension/src/LoadGameCompatibility.cpp
deleted file mode 100644
index 71435a4..0000000
--- a/extension/src/LoadGameCompatibility.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-#include "GameSingleton.hpp"
-
-#include <godot_cpp/classes/file_access.hpp>
-#include <godot_cpp/variant/utility_functions.hpp>
-
-#include "openvic/utility/BMP.hpp"
-
-#include "Utilities.hpp"
-
-using namespace godot;
-using namespace OpenVic;
-
-Error GameSingleton::_load_province_identifier_file_compatibility_mode(String const& file_path) {
- UtilityFunctions::print("Loading compatibility mode province identifier file: ", file_path);
-
- const Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ);
- Error err = FileAccess::get_open_error();
- if (err != OK || file.is_null()) {
- UtilityFunctions::push_error("Failed to load compatibility mode province identifier file: ", file_path);
- if (err == OK) err = FAILED;
- } else {
- int line_number = 0;
- while (!file->eof_reached()) {
- const PackedStringArray line = file->get_csv_line(";");
- line_number++;
-
- if (line.is_empty() || (line.size() == 1 && line[0].is_empty()))
- continue;
-
- if (line_number < 2) continue; // skip header line
- index_t id = NULL_INDEX;
- colour_t colour = NULL_COLOUR;
- if (line.size() > 0) {
- if (line[0].is_empty()) {
- id = game_manager.map.get_province_count() + 1;
- } else if (line[0].is_valid_int()) {
- const int64_t val = line[0].to_int();
- if (val > NULL_INDEX && val <= MAX_INDEX) id = val;
- }
- for (int i = 1; i < 4; ++i) {
- if (line.size() > i) {
- if (line[i].is_valid_int()) {
- const int64_t int_val = line[i].to_int();
- if (int_val >= NULL_COLOUR && int_val <= FULL_COLOUR) {
- colour = (colour << 8) | int_val;
- continue;
- }
- } else if (line[i].is_valid_float()) {
- const double double_val = line[i].to_float();
- if (std::trunc(double_val) == double_val) {
- const int64_t int_val = double_val;
- if (int_val >= NULL_COLOUR && int_val <= FULL_COLOUR) {
- colour = (colour << 8) | int_val;
- continue;
- }
- }
- }
- }
- colour = NULL_COLOUR;
- break;
- }
- }
- if (id == NULL_INDEX || colour == NULL_COLOUR) {
- UtilityFunctions::push_error("Invalid province ID-colour entry \"", line, "\" on line ", line_number, " in file: ", file_path);
- err = FAILED;
- continue;
- }
- static const std::string province_prefix = "PROV";
- if (game_manager.map.add_province(province_prefix + std::to_string(id), colour) != SUCCESS) err = FAILED;
- }
- }
- game_manager.map.lock_provinces();
- return err;
-}
-
-Error GameSingleton::_load_terrain_variants_compatibility_mode(String const& terrain_image_path, String const& terrain_texturesheet_path) {
- // Read BMP's palette to determine terrain variant colours which texture they're associated with
- BMP bmp;
- if (bmp.open(godot_to_std_string(terrain_image_path).c_str()) != SUCCESS || bmp.read_header() != SUCCESS || bmp.read_palette() != SUCCESS) {
- UtilityFunctions::push_error("Failed to read BMP palette from compatibility mode terrain image: ", terrain_image_path);
- return FAILED;
- }
- std::vector<colour_t> const& palette = bmp.get_palette();
- static constexpr int32_t SHEET_DIMS = 8, PALETTE_SIZE = SHEET_DIMS * SHEET_DIMS;
- if (palette.size() == 0 || palette.size() < PALETTE_SIZE) {
- UtilityFunctions::push_error("Invalid BMP palette size for terrain image: ", static_cast<uint64_t>(palette.size()), " (expected ", PALETTE_SIZE, ")");
- return FAILED;
- }
-
- // Load the terrain texture sheet and prepare to slice it up
- Ref<Image> terrain_sheet = load_godot_image(terrain_texturesheet_path);
- if (terrain_sheet.is_null()) {
- UtilityFunctions::push_error("Failed to load terrain texture sheet: ", terrain_texturesheet_path);
- return FAILED;
- }
- terrain_sheet->flip_y();
- const int32_t sheet_width = terrain_sheet->get_width(), sheet_height = terrain_sheet->get_height();
- if (sheet_width < 1 || sheet_width % SHEET_DIMS != 0 || sheet_width != sheet_height) {
- UtilityFunctions::push_error("Invalid terrain texture sheet dims: ", sheet_width, "x", sheet_height, " (must be square with dims positive multiples of ", SHEET_DIMS, ")");
- return FAILED;
- }
- const int32_t slice_size = sheet_width / SHEET_DIMS;
-
- {
- Ref<Image> water_image = Image::create(slice_size, slice_size, false, terrain_sheet->get_format());
- ERR_FAIL_NULL_V_EDMSG(water_image, FAILED, "Failed to create water terrain image");
- water_image->fill({ 0.0f, 0.0f, 1.0f });
- terrain_variants.add_item({ "terrain_water", 0xFFFFFF, water_image });
- }
- Error err = OK;
- for (int32_t idx = 0; idx < PALETTE_SIZE; ++idx) {
- const Rect2i slice { (idx % SHEET_DIMS) * slice_size, (7 - (idx / SHEET_DIMS)) * slice_size, slice_size, slice_size };
- const Ref<Image> terrain_image = terrain_sheet->get_region(slice);
- if (terrain_image.is_null() || terrain_image->is_empty()) {
- UtilityFunctions::push_error("Failed to extract terrain texture slice ", slice, " from ", terrain_texturesheet_path);
- err = FAILED;
- continue;
- }
- if (terrain_variants.add_item({ "terrain_" + std::to_string(idx), palette[idx], terrain_image }) != SUCCESS) err = FAILED;
- }
- terrain_variants.lock();
- if (_generate_terrain_texture_array() != OK) return FAILED;
- return err;
-}
-
-Error GameSingleton::load_defines_compatibility_mode(String const& file_path) {
- static const String province_identifier_file = "/map/definition.csv";
- static const String province_image_file = "/map/provinces.bmp";
- static const String terrain_image_file = "/map/terrain.bmp";
- static const String terrain_texture_dir = "/map/terrain/texturesheet.tga";
-
- Error err = OK;
- if (_load_province_identifier_file_compatibility_mode(file_path + province_identifier_file) != OK) {
- UtilityFunctions::push_error("Failed to load province identifiers!");
- err = FAILED;
- }
- game_manager.map.lock_water_provinces();
- game_manager.map.lock_regions();
- if (_load_terrain_variants_compatibility_mode(file_path + terrain_image_file, file_path + terrain_texture_dir) != OK) {
- UtilityFunctions::push_error("Failed to load terrain variants!");
- err = FAILED;
- }
- if (_load_map_images(file_path + province_image_file, file_path + terrain_image_file, true) != OK) {
- UtilityFunctions::push_error("Failed to load map images!");
- err = FAILED;
- }
- game_manager.good_manager.lock_goods();
- if (_load_hardcoded_defines() != OK) {
- UtilityFunctions::push_error("Failed to hardcoded defines!");
- err = FAILED;
- }
- return err;
-}
diff --git a/extension/src/LoadGameOpenVic.cpp b/extension/src/LoadGameOpenVic.cpp
deleted file mode 100644
index 627578f..0000000
--- a/extension/src/LoadGameOpenVic.cpp
+++ /dev/null
@@ -1,469 +0,0 @@
-#include "GameSingleton.hpp"
-
-#include <godot_cpp/classes/file_access.hpp>
-#include <godot_cpp/classes/json.hpp>
-#include <godot_cpp/variant/utility_functions.hpp>
-
-#include "Utilities.hpp"
-
-using namespace godot;
-using namespace OpenVic;
-
-static Error _load_json_file(String const& file_description, String const& file_path, Variant& result) {
- result.clear();
- UtilityFunctions::print("Loading ", file_description, " file: ", file_path);
- const Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::ModeFlags::READ);
- Error err = FileAccess::get_open_error();
- if (err != OK || file.is_null()) {
- UtilityFunctions::push_error("Failed to load ", file_description, " file: ", file_path);
- return err == OK ? FAILED : err;
- }
- const String json_string = file->get_as_text();
- Ref<JSON> json;
- json.instantiate();
- err = json->parse(json_string);
- if (err != OK) {
- UtilityFunctions::push_error("Failed to parse ", file_description, " file as JSON: ", file_path,
- "\nError at line ", json->get_error_line(), ": ", json->get_error_message());
- return err;
- }
- result = json->get_data();
- return err;
-}
-
-using parse_json_entry_func_t = std::function<Error(String const&, Variant const&)>;
-
-static Error _parse_json_dictionary_file(String const& file_description, String const& file_path,
- String const& identifier_prefix, parse_json_entry_func_t parse_entry) {
- Variant json_var;
- Error err = _load_json_file(file_description, file_path, json_var);
- if (err != OK) return err;
- const Variant::Type type = json_var.get_type();
- if (type != Variant::DICTIONARY) {
- UtilityFunctions::push_error("Invalid ", file_description, " JSON: root has type ",
- Variant::get_type_name(type), " (expected Dictionary)");
- return FAILED;
- }
- Dictionary const& dict = json_var;
- const Array identifiers = dict.keys();
- for (int64_t idx = 0; idx < identifiers.size(); ++idx) {
- String const& identifier = identifiers[idx];
- Variant const& entry = dict[identifier];
- if (identifier.is_empty()) {
- UtilityFunctions::push_error("Empty identifier in ", file_description, " file with entry: ", entry);
- err = FAILED;
- continue;
- }
- if (!identifier.begins_with(identifier_prefix))
- UtilityFunctions::push_warning("Identifier in ", file_description, " file missing \"", identifier_prefix, "\" prefix: ", identifier);
- if (parse_entry(identifier, entry) != OK) err = FAILED;
- }
- return err;
-}
-
-static colour_t _parse_colour(Variant const& var) {
- const Variant::Type type = var.get_type();
- if (type == Variant::ARRAY) {
- Array const& colour_array = var;
- if (colour_array.size() == 3) {
- colour_t colour = NULL_COLOUR;
- for (int jdx = 0; jdx < 3; ++jdx) {
- Variant const& var = colour_array[jdx];
- if (var.get_type() != Variant::FLOAT) return NULL_COLOUR;
- const double colour_double = var;
- if (std::trunc(colour_double) != colour_double) return NULL_COLOUR;
- const int64_t colour_int = static_cast<int64_t>(colour_double);
- if (colour_int < 0 || colour_int > 255) return NULL_COLOUR;
- colour = (colour << 8) | colour_int;
- }
- return colour;
- }
- } else if (type == Variant::STRING) {
- String const& colour_string = var;
- if (colour_string.is_valid_hex_number()) {
- const int64_t colour_int = colour_string.hex_to_int();
- if (colour_int != NULL_COLOUR && colour_int <= MAX_COLOUR_RGB)
- return colour_int;
- }
- }
- return NULL_COLOUR;
-}
-
-Error GameSingleton::_parse_province_identifier_entry(String const& identifier, Variant const& entry) {
- const colour_t colour = _parse_colour(entry);
- if (colour == NULL_COLOUR || colour > MAX_COLOUR_RGB) {
- UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry);
- return FAILED;
- }
- return ERR(game_manager.map.add_province(godot_to_std_string(identifier), colour));
-}
-
-Error GameSingleton::_load_province_identifier_file(String const& file_path) {
- const Error err = _parse_json_dictionary_file("province identifier", file_path, "prov_",
- [this](String const& identifier, Variant const& entry) -> Error {
- return _parse_province_identifier_entry(identifier, entry);
- });
- game_manager.map.lock_provinces();
- return err;
-}
-
-Error GameSingleton::_load_water_province_file(String const& file_path) {
- Variant json_var;
- Error err = _load_json_file("water province", file_path, json_var);
- if (err != OK) return err;
- Variant::Type type = json_var.get_type();
- if (type != Variant::ARRAY) {
- UtilityFunctions::push_error("Invalid water province JSON: root has type ",
- Variant::get_type_name(type), " (expected Array)");
- err = FAILED;
- } else {
- Array const& array = json_var;
- for (int64_t idx = 0; idx < array.size(); ++idx) {
- Variant const& entry = array[idx];
- type = entry.get_type();
- if (type != Variant::STRING) {
- UtilityFunctions::push_error("Invalid water province identifier: ", entry);
- err = FAILED;
- continue;
- }
- String const& identifier = entry;
- if (game_manager.map.set_water_province(godot_to_std_string(identifier)) != SUCCESS)
- err = FAILED;
- }
- }
- game_manager.map.lock_water_provinces();
- return err;
-}
-
-Error GameSingleton::_parse_region_entry(String const& identifier, Variant const& entry) {
- Error err = OK;
- Variant::Type type = entry.get_type();
- std::vector<std::string> province_identifiers;
- if (type == Variant::ARRAY) {
- Array const& province_array = entry;
- for (int64_t idx = 0; idx < province_array.size(); ++idx) {
- Variant const& province_var = province_array[idx];
- type = province_var.get_type();
- if (type == Variant::STRING) {
- String const& province_string = province_var;
- province_identifiers.push_back(godot_to_std_string(province_string));
- } else {
- UtilityFunctions::push_error("Invalid province identifier for region \"", identifier, "\": ", entry);
- err = FAILED;
- }
- }
- }
- if (province_identifiers.empty()) {
- UtilityFunctions::push_error("Invalid province list for region \"", identifier, "\": ", entry);
- return FAILED;
- }
- std::vector<std::string_view> province_identifier_views;
- for (std::string const& str : province_identifiers) {
- province_identifier_views.push_back(str);
- }
- return ERR(game_manager.map.add_region(godot_to_std_string(identifier), province_identifier_views));
-}
-
-Error GameSingleton::_load_region_file(String const& file_path) {
- const Error err = _parse_json_dictionary_file("region", file_path, "region_",
- [this](String const& identifier, Variant const& entry) -> Error {
- return _parse_region_entry(identifier, entry);
- });
- game_manager.map.lock_regions();
- return err;
-}
-
-Error GameSingleton::_parse_terrain_entry(String const& identifier, Variant const& entry, String const& terrain_texture_dir_path) {
- const colour_t colour = _parse_colour(entry);
- if (colour == NULL_COLOUR || colour > MAX_COLOUR_RGB) {
- UtilityFunctions::push_error("Invalid colour for terrain texture \"", identifier, "\": ", entry);
- return FAILED;
- }
- const String terrain_path = terrain_texture_dir_path + identifier;
- const Ref<Image> terrain_image = load_godot_image(terrain_path);
- if (terrain_image.is_null()) {
- UtilityFunctions::push_error("Failed to load terrain image: ", terrain_path);
- return FAILED;
- }
- return ERR(terrain_variants.add_item({ godot_to_std_string(identifier), colour, terrain_image }));
-}
-
-Error GameSingleton::_load_terrain_variants(String const& terrain_identifiers_path, String const& terrain_texture_dir_path) {
- Error err = _parse_json_dictionary_file("terrain variants", terrain_identifiers_path, "",
- [this, terrain_texture_dir_path](String const& identifier, Variant const& entry) -> Error {
- return _parse_terrain_entry(identifier, entry, terrain_texture_dir_path + String { "/" });
- });
- terrain_variants.lock();
- if (_generate_terrain_texture_array() != OK) return FAILED;
- return err;
-}
-
-Error GameSingleton::_generate_terrain_texture_array() {
- Error err = OK;
- if (terrain_variants.get_item_count() == 0) {
- UtilityFunctions::push_error("Failed to load terrain textures!");
- return FAILED;
- }
- // TerrainVariant count is limited by the data type representing it in the map image
- if (terrain_variants.get_item_count() > TerrainVariant::MAX_INDEX) {
- UtilityFunctions::push_error("Too many terrain textures - all after the first ", MAX_INDEX, " will be ignored");
- err = FAILED;
- }
-
- Array terrain_images;
- for (size_t i = 0; i < terrain_variants.get_item_count() && i < TerrainVariant::MAX_INDEX; ++i) {
- TerrainVariant const& var = *terrain_variants.get_item_by_index(i);
- terrain_variant_map[var.get_colour()] = i;
- terrain_images.append(var.get_image());
- }
-
- terrain_texture.instantiate();
- if (terrain_texture->create_from_images(terrain_images) != OK) {
- UtilityFunctions::push_error("Failed to create terrain texture array!");
- return FAILED;
- }
- return err;
-}
-
-Error GameSingleton::_load_map_images(String const& province_image_path, String const& terrain_image_path, bool flip_vertical) {
- if (province_shape_texture.is_valid()) {
- UtilityFunctions::push_error("Map images have already been loaded, cannot load: ", province_image_path, " and ", terrain_image_path);
- return FAILED;
- }
-
- // Load images
- Ref<Image> province_image = load_godot_image(province_image_path);
- if (province_image.is_null()) {
- UtilityFunctions::push_error("Failed to load province image: ", province_image_path);
- return FAILED;
- }
- Ref<Image> terrain_image = load_godot_image(terrain_image_path);
- if (terrain_image.is_null()) {
- UtilityFunctions::push_error("Failed to load terrain image: ", terrain_image_path);
- return FAILED;
- }
-
- if (flip_vertical) {
- province_image->flip_y();
- terrain_image->flip_y();
- }
-
- // Validate dimensions and format
- Error err = OK;
- const Vector2i province_dims = province_image->get_size(), terrain_dims = terrain_image->get_size();
- if (province_dims.x < 1 || province_dims.y < 1) {
- UtilityFunctions::push_error("Invalid dimensions (", province_dims.x, "x", province_dims.y, ") for province image: ", province_image_path);
- err = FAILED;
- }
- if (province_dims != terrain_dims) {
- UtilityFunctions::push_error("Invalid dimensions (", terrain_dims.x, "x", terrain_dims.y, ") for terrain image: ",
- terrain_image_path, " (must match province image: (", province_dims.x, "x", province_dims.x, "))");
- err = FAILED;
- }
- static constexpr Image::Format expected_format = Image::FORMAT_RGB8;
- if (province_image->get_format() == Image::FORMAT_RGBA8) province_image->convert(expected_format);
- if (terrain_image->get_format() == Image::FORMAT_RGBA8) terrain_image->convert(expected_format);
- if (province_image->get_format() != expected_format) {
- UtilityFunctions::push_error("Invalid format (", province_image->get_format(), ", should be ", expected_format, ") for province image: ", province_image_path);
- err = FAILED;
- }
- if (terrain_image->get_format() != expected_format) {
- UtilityFunctions::push_error("Invalid format (", terrain_image->get_format(), ", should be ", expected_format, ") for terrain image: ", terrain_image_path);
- err = FAILED;
- }
- if (err != OK) return err;
-
- // Generate interleaved province and terrain ID image
- if (game_manager.map.generate_province_shape_image(province_dims.x, province_dims.y, province_image->get_data().ptr(),
- terrain_image->get_data().ptr(), terrain_variant_map, true) != SUCCESS) err = FAILED;
-
- static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF;
- // For each dimension of the image, this finds the small number of equal subdivisions required get the individual texture dims under GPU_DIM_LIMIT
- for (int i = 0; i < 2; ++i)
- for (image_subdivisions[i] = 1; province_dims[i] / image_subdivisions[i] > GPU_DIM_LIMIT ||
- province_dims[i] % image_subdivisions[i] != 0; ++image_subdivisions[i]);
-
- Map::shape_pixel_t const* province_shape_data = game_manager.map.get_province_shape_image().data();
- const Vector2i divided_dims = province_dims / image_subdivisions;
- Array province_shape_images;
- province_shape_images.resize(image_subdivisions.x * image_subdivisions.y);
- for (int32_t v = 0; v < image_subdivisions.y; ++v) {
- for (int32_t u = 0; u < image_subdivisions.x; ++u) {
- PackedByteArray index_data_array;
- index_data_array.resize(divided_dims.x * divided_dims.y * sizeof(Map::shape_pixel_t));
-
- for (int32_t y = 0; y < divided_dims.y; ++y)
- memcpy(index_data_array.ptrw() + y * divided_dims.x * sizeof(Map::shape_pixel_t),
- province_shape_data + (v * divided_dims.y + y) * province_dims.x + u * divided_dims.x,
- divided_dims.x * sizeof(Map::shape_pixel_t));
-
- const Ref<Image> province_shape_subimage = Image::create_from_data(divided_dims.x, divided_dims.y, false, Image::FORMAT_RGB8, index_data_array);
- if (province_shape_subimage.is_null()) {
- UtilityFunctions::push_error("Failed to create province shape image (", u, ", ", v, ")");
- err = FAILED;
- }
- province_shape_images[u + v * image_subdivisions.x] = province_shape_subimage;
- }
- }
-
- province_shape_texture.instantiate();
- if (province_shape_texture->create_from_images(province_shape_images) != OK) {
- UtilityFunctions::push_error("Failed to create terrain texture array!");
- err = FAILED;
- }
-
- if (_update_colour_image() != OK) err = FAILED;
-
- return err;
-}
-
-Error GameSingleton::_parse_good_entry(String const& identifier, Variant const& entry) {
- if (entry.get_type() != Variant::DICTIONARY) {
- UtilityFunctions::push_error("Invalid good entry for ", identifier, ": ", entry);
- return FAILED;
- }
- Dictionary const& dict = entry;
-
- static const String key_category = "category";
- Variant const& var_category = dict.get(key_category, "");
- String category;
- if (var_category.get_type() == Variant::STRING) category = var_category;
- else UtilityFunctions::push_error("Invalid good category for ", identifier, ": ", var_category);
-
- static const String key_base_price = "base_price";
- Variant const& var_base_price = dict.get(key_base_price, NULL_PRICE);
- price_t base_price = NULL_PRICE;
- if (var_base_price.get_type() == Variant::FLOAT) base_price = var_base_price;
- else UtilityFunctions::push_error("Invalid good base price for ", identifier, ": ", var_base_price);
-
- static const String key_colour = "colour";
- Variant const& var_colour = dict.get(key_colour, "");
- const colour_t colour = _parse_colour(var_colour);
- if (colour > MAX_COLOUR_RGB) {
- UtilityFunctions::push_error("Invalid good colour for ", identifier, ": ", var_colour);
- return FAILED;
- }
-
- static const String key_default_available = "default_available";
- Variant const& var_default_available = dict.get(key_default_available, true);
- bool default_available = false;
- if (var_default_available.get_type() == Variant::BOOL) default_available = var_default_available;
- else UtilityFunctions::push_error("Invalid good available default bool value for ", identifier, ": ", var_default_available);
-
- static const String key_tradeable = "tradeable";
- Variant const& var_tradeable = dict.get(key_tradeable, true);
- bool tradeable = false;
- if (var_tradeable.get_type() == Variant::BOOL) tradeable = var_tradeable;
- else UtilityFunctions::push_error("Invalid good tradeable bool value for ", identifier, ": ", var_tradeable);
-
- static const String key_currency = "currency";
- Variant const& var_currency = dict.get(key_currency, true);
- bool currency = false;
- if (var_currency.get_type() == Variant::BOOL) currency = var_currency;
- else UtilityFunctions::push_error("Invalid good currency bool value for ", identifier, ": ", var_currency);
-
- static const String key_overseas_maintenance = "overseas_maintenance";
- Variant const& var_overseas_maintenance = dict.get(key_overseas_maintenance, true);
- bool overseas_maintenance = false;
- if (var_overseas_maintenance.get_type() == Variant::BOOL) overseas_maintenance = var_overseas_maintenance;
- else UtilityFunctions::push_error("Invalid good overseas maintenance bool value for ", identifier, ": ", var_overseas_maintenance);
-
- return ERR(game_manager.good_manager.add_good(godot_to_std_string(identifier), colour, godot_to_std_string(category),
- base_price, default_available, tradeable, currency, overseas_maintenance));
-}
-
-Error GameSingleton::_load_goods(String const& defines_path, String const& icons_dir_path) {
- Error err = _parse_json_dictionary_file("good", defines_path, "good_",
- [this](String const& identifier, Variant const& entry) -> Error {
- return _parse_good_entry(identifier, entry);
- });
- game_manager.good_manager.lock_goods();
- for (Good const& good : game_manager.good_manager.get_goods()) {
- const String path = icons_dir_path + String { "/" } + std_to_godot_string(good.get_identifier()) + ".png";
- const Ref<Image> image = load_godot_image(path);
- if (image.is_null()) {
- UtilityFunctions::push_error("Failed to load good icon image: ", path);
- err = FAILED;
- continue;
- }
- const Ref<Texture> tex = ImageTexture::create_from_image(image);
- if (tex.is_null()) {
- UtilityFunctions::push_error("Failed to generate good icon texture: ", path);
- err = FAILED;
- continue;
- }
- good_icons[std_to_godot_string(good.get_identifier())] = tex;
- }
- return err;
-}
-
-StringName const& GameSingleton::get_province_identifier_file_key() {
- static const StringName key = "province_identifiers";
- return key;
-}
-StringName const& GameSingleton::get_water_province_file_key() {
- static const StringName key = "water_provinces";
- return key;
-}
-StringName const& GameSingleton::get_region_file_key() {
- static const StringName key = "regions";
- return key;
-}
-StringName const& GameSingleton::get_terrain_variant_file_key() {
- static const StringName key = "terrain_variants";
- return key;
-}
-StringName const& GameSingleton::get_terrain_texture_dir_key() {
- static const StringName key = "terrain_textures";
- return key;
-}
-StringName const& GameSingleton::get_province_image_file_key() {
- static const StringName key = "province_image";
- return key;
-}
-StringName const& GameSingleton::get_terrain_image_file_key() {
- static const StringName key = "terrain_image";
- return key;
-}
-StringName const& GameSingleton::get_goods_file_key() {
- static const StringName key = "goods";
- return key;
-}
-StringName const& GameSingleton::get_good_icons_dir_key() {
- static const StringName key = "good_icons";
- return key;
-}
-
-Error GameSingleton::load_defines(Dictionary const& file_dict) {
- Error err = OK;
- if (_load_province_identifier_file(file_dict.get(get_province_identifier_file_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load province identifiers!");
- err = FAILED;
- }
- if (_load_water_province_file(file_dict.get(get_water_province_file_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load water provinces!");
- err = FAILED;
- }
- if (_load_region_file(file_dict.get(get_region_file_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load regions!");
- err = FAILED;
- }
- if (_load_terrain_variants(file_dict.get(get_terrain_variant_file_key(), ""),
- file_dict.get(get_terrain_texture_dir_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load terrain variants!");
- err = FAILED;
- }
- if (_load_map_images(file_dict.get(get_province_image_file_key(), ""), file_dict.get(get_terrain_image_file_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load map images!");
- err = FAILED;
- }
- if (_load_goods(file_dict.get(get_goods_file_key(), ""), file_dict.get(get_good_icons_dir_key(), "")) != OK) {
- UtilityFunctions::push_error("Failed to load goods!");
- err = FAILED;
- }
- if (_load_hardcoded_defines() != OK) {
- UtilityFunctions::push_error("Failed to hardcoded defines!");
- err = FAILED;
- }
- return err;
-}
diff --git a/extension/src/Checksum.hpp b/extension/src/openvic-extension/Checksum.hpp
index b12a9cd..b12a9cd 100644
--- a/extension/src/Checksum.hpp
+++ b/extension/src/openvic-extension/Checksum.hpp
diff --git a/extension/src/GameSingleton.cpp b/extension/src/openvic-extension/GameSingleton.cpp
index 18fd67a..a164b23 100644
--- a/extension/src/GameSingleton.cpp
+++ b/extension/src/openvic-extension/GameSingleton.cpp
@@ -2,9 +2,9 @@
#include <godot_cpp/variant/utility_functions.hpp>
-#include "openvic/utility/Logger.hpp"
+#include <openvic-simulation/utility/Logger.hpp>
-#include "Utilities.hpp"
+#include "openvic-extension/Utilities.hpp"
using namespace godot;
using namespace OpenVic;
@@ -22,8 +22,8 @@ GameSingleton* GameSingleton::singleton = nullptr;
void GameSingleton::_bind_methods() {
ClassDB::bind_static_method("GameSingleton", D_METHOD("setup_logger"), &GameSingleton::setup_logger);
- ClassDB::bind_method(D_METHOD("load_defines", "file_dict"), &GameSingleton::load_defines);
- ClassDB::bind_method(D_METHOD("load_defines_compatibility_mode", "file_path"), &GameSingleton::load_defines_compatibility_mode);
+ ClassDB::bind_method(D_METHOD("load_defines_compatibility_mode", "file_paths"), &GameSingleton::load_defines_compatibility_mode);
+ ClassDB::bind_method(D_METHOD("lookup_file", "path"), &GameSingleton::lookup_file);
ClassDB::bind_method(D_METHOD("setup_game"), &GameSingleton::setup_game);
ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &GameSingleton::get_province_index_from_uv_coords);
@@ -58,16 +58,6 @@ void GameSingleton::_bind_methods() {
ADD_SIGNAL(MethodInfo("state_updated"));
ADD_SIGNAL(MethodInfo("province_selected", PropertyInfo(Variant::INT, "index")));
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_identifier_file_key"), &GameSingleton::get_province_identifier_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_water_province_file_key"), &GameSingleton::get_water_province_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_region_file_key"), &GameSingleton::get_region_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_terrain_variant_file_key"), &GameSingleton::get_terrain_variant_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_terrain_texture_dir_key"), &GameSingleton::get_terrain_texture_dir_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_image_file_key"), &GameSingleton::get_province_image_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_terrain_image_file_key"), &GameSingleton::get_terrain_image_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_goods_file_key"), &GameSingleton::get_goods_file_key);
- ClassDB::bind_static_method("GameSingleton", D_METHOD("get_good_icons_dir_key"), &GameSingleton::get_good_icons_dir_key);
-
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_province_key"), &GameSingleton::get_province_info_province_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_region_key"), &GameSingleton::get_province_info_region_key);
ClassDB::bind_static_method("GameSingleton", D_METHOD("get_province_info_life_rating_key"), &GameSingleton::get_province_info_life_rating_key);
@@ -95,7 +85,7 @@ void GameSingleton::_bind_methods() {
}
void GameSingleton::draw_pie_chart(Ref<Image> image,
- Array const& stopAngles, Array const& colours, float radius,
+ Array const& stopAngles, Array const& colours, float radius,
Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
Color trim_colour, float trim_size, float gradient_falloff, float gradient_base,
bool donut, bool donut_inner_trim, float donut_inner_radius) {
@@ -115,7 +105,7 @@ void GameSingleton::_on_state_updated() {
}
/* REQUIREMENTS:
- * MAP-21, MAP-23, MAP-25, MAP-32, MAP-33
+ * MAP-21, MAP-23, MAP-25, MAP-32, MAP-33, MAP-34
*/
GameSingleton::GameSingleton() : game_manager { [this]() { _on_state_updated(); } },
terrain_variants { "terrain variants" } {
@@ -125,98 +115,19 @@ GameSingleton::GameSingleton() : game_manager { [this]() { _on_state_updated();
void GameSingleton::setup_logger() {
Logger::set_info_func([](std::string&& str) { UtilityFunctions::print(std_to_godot_string(str)); });
+ Logger::set_warning_func([](std::string&& str) { UtilityFunctions::push_warning(std_to_godot_string(str)); });
Logger::set_error_func([](std::string&& str) { UtilityFunctions::push_error(std_to_godot_string(str)); });
}
-Error GameSingleton::_load_hardcoded_defines() {
- Error err = OK;
-
- static constexpr colour_t LOW_ALPHA_VALUE = float_to_alpha_value(0.4f);
- static constexpr colour_t HIGH_ALPHA_VALUE = float_to_alpha_value(0.7f);
- using mapmode_t = std::pair<std::string, Mapmode::colour_func_t>;
- const std::vector<mapmode_t> mapmodes {
- { "mapmode_terrain",
- [](Map const&, Province const& province) -> colour_t {
- return LOW_ALPHA_VALUE | (province.is_water() ? 0x4287F5 : 0x0D7017);
- } },
- { "mapmode_province",
- [](Map const&, Province const& province) -> colour_t {
- return HIGH_ALPHA_VALUE | province.get_colour();
- } },
- { "mapmode_region",
- [](Map const&, Province const& province) -> colour_t {
- Region const* region = province.get_region();
- if (region != nullptr) return HIGH_ALPHA_VALUE | region->get_colour();
- return NULL_COLOUR;
- } },
- { "mapmode_index",
- [](Map const& map, Province const& province) -> colour_t {
- const colour_t f = fraction_to_colour_byte(province.get_index(), map.get_province_count() + 1);
- return HIGH_ALPHA_VALUE | (f << 16) | (f << 8) | f;
- } },
- { "mapmode_rgo",
- [](Map const& map, Province const& province) -> colour_t {
- Good const* rgo = province.get_rgo();
- if (rgo != nullptr) return HIGH_ALPHA_VALUE | rgo->get_colour();
- return NULL_COLOUR;
- } },
- { "mapmode_infrastructure",
- [](Map const& map, Province const& province) -> colour_t {
- Building const* railroad = province.get_building_by_identifier("building_railroad");
- if (railroad != nullptr) {
- colour_t val = fraction_to_colour_byte(railroad->get_level(), railroad->get_type().get_max_level() + 1, 0.5f, 1.0f);
- switch (railroad->get_expansion_state()) {
- case Building::ExpansionState::CannotExpand: val <<= 16; break;
- case Building::ExpansionState::CanExpand: break;
- default: val <<= 8; break;
- }
- return HIGH_ALPHA_VALUE | val;
- }
- return NULL_COLOUR;
- } },
- { "mapmode_population",
- [](Map const& map, Province const& province) -> colour_t {
- return HIGH_ALPHA_VALUE | (fraction_to_colour_byte(province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f) << 8);
- } },
- { "mapmode_culture",
- [](Map const& map, Province const& province) -> colour_t {
- distribution_t const& cultures = province.get_culture_distribution();
- if (!cultures.empty()) {
- // This breaks if replaced with distribution_t::value_type, something
- // about operator=(volatile const&) being deleted.
- std::pair<HasIdentifierAndColour const*, float> culture = *cultures.begin();
- for (distribution_t::value_type const p : cultures) {
- if (p.second > culture.second) culture = p;
- }
- return HIGH_ALPHA_VALUE | culture.first->get_colour();
- }
- return NULL_COLOUR;
- } }
- };
- for (mapmode_t const& mapmode : mapmodes)
- if (game_manager.map.add_mapmode(mapmode.first, mapmode.second) != SUCCESS)
- err = FAILED;
- game_manager.map.lock_mapmodes();
-
- using building_type_t = std::tuple<std::string, Building::level_t, Timespan>;
- const std::vector<building_type_t> building_types {
- { "building_fort", 4, 8 }, { "building_naval_base", 6, 15 }, { "building_railroad", 5, 10 }
- };
- for (building_type_t const& type : building_types)
- if (game_manager.building_manager.add_building_type(std::get<0>(type), std::get<1>(type), std::get<2>(type)) != SUCCESS)
- err = FAILED;
- game_manager.building_manager.lock_building_types();
-
- return err;
-}
-
GameSingleton::~GameSingleton() {
ERR_FAIL_COND(singleton != this);
singleton = nullptr;
}
Error GameSingleton::setup_game() {
- return ERR(game_manager.setup());
+ bool ret = game_manager.setup();
+ ret &= dataloader.load_pop_history(game_manager, "history/pops/" + game_manager.get_today().to_string());
+ return ERR(ret);
}
int32_t GameSingleton::get_province_index_from_uv_coords(Vector2 const& coords) const {
@@ -340,8 +251,8 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const {
building_dict[get_building_info_building_key()] = std_to_godot_string(building.get_identifier());
building_dict[get_building_info_level_key()] = static_cast<int32_t>(building.get_level());
building_dict[get_building_info_expansion_state_key()] = static_cast<int32_t>(building.get_expansion_state());
- building_dict[get_building_info_start_date_key()] = std_to_godot_string(static_cast<std::string>(building.get_start_date()));
- building_dict[get_building_info_end_date_key()] = std_to_godot_string(static_cast<std::string>(building.get_end_date()));
+ building_dict[get_building_info_start_date_key()] = std_to_godot_string(building.get_start_date().to_string());
+ building_dict[get_building_info_end_date_key()] = std_to_godot_string(building.get_end_date().to_string());
building_dict[get_building_info_expansion_progress_key()] = building.get_expansion_progress();
buildings_array[idx] = building_dict;
@@ -381,14 +292,14 @@ Ref<Texture> GameSingleton::get_province_colour_texture() const {
Error GameSingleton::_update_colour_image() {
static PackedByteArray colour_data_array;
- static constexpr int64_t colour_data_array_size = (MAX_INDEX + 1) * Map::MAPMODE_COLOUR_SIZE;
+ static constexpr int64_t colour_data_array_size = (static_cast<int64_t>(Province::MAX_INDEX) + 1) * Map::MAPMODE_COLOUR_SIZE;
colour_data_array.resize(colour_data_array_size);
Error err = OK;
- if (game_manager.map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw()) != SUCCESS)
+ if (!game_manager.map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw()))
err = FAILED;
- static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(index_t) * 4);
+ static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4);
if (province_colour_image.is_null()) {
province_colour_image.instantiate();
ERR_FAIL_NULL_V_EDMSG(province_colour_image, FAILED,
@@ -436,7 +347,7 @@ void GameSingleton::set_selected_province(int32_t index) {
}
Error GameSingleton::expand_building(int32_t province_index, String const& building_type_identifier) {
- if (game_manager.expand_building(province_index, godot_to_std_string(building_type_identifier)) != SUCCESS) {
+ if (!game_manager.expand_building(province_index, godot_to_std_string(building_type_identifier))) {
UtilityFunctions::push_error("Failed to expand ", building_type_identifier, " at province index ", province_index);
return FAILED;
}
@@ -476,7 +387,7 @@ bool GameSingleton::can_decrease_speed() const {
}
String GameSingleton::get_longform_date() const {
- return std_to_godot_string(static_cast<std::string>(game_manager.get_today()));
+ return std_to_godot_string(game_manager.get_today().to_string());
}
void GameSingleton::try_tick() {
diff --git a/extension/src/GameSingleton.hpp b/extension/src/openvic-extension/GameSingleton.hpp
index cd8cdd0..bd6b73c 100644
--- a/extension/src/GameSingleton.hpp
+++ b/extension/src/openvic-extension/GameSingleton.hpp
@@ -3,9 +3,11 @@
#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/texture2d_array.hpp>
-#include "openvic/GameManager.hpp"
+#include <openvic-simulation/GameManager.hpp>
+#include <openvic-simulation/dataloader/Dataloader.hpp>
namespace OpenVic {
+
struct TerrainVariant : HasIdentifierAndColour {
friend class GameSingleton;
@@ -14,19 +16,22 @@ namespace OpenVic {
TerrainVariant(const std::string_view new_identfier, colour_t new_colour,
godot::Ref<godot::Image> const& new_image);
+
public:
- static constexpr size_t MAX_INDEX = 1 << (8 * sizeof(Map::terrain_t));
+ static constexpr size_t MAX_TERRIN_VARIANT_COUNT = 1 << (8 * sizeof(Map::terrain_t));
TerrainVariant(TerrainVariant&&) = default;
godot::Ref<godot::Image> get_image() const;
};
+
class GameSingleton : public godot::Object {
GDCLASS(GameSingleton, godot::Object)
static GameSingleton* singleton;
GameManager game_manager;
+ Dataloader dataloader;
godot::Vector2i image_subdivisions;
godot::Ref<godot::Texture2DArray> province_shape_texture;
@@ -38,27 +43,11 @@ namespace OpenVic {
godot::Ref<godot::Texture2DArray> terrain_texture;
godot::Dictionary good_icons;
- godot::Error _parse_province_identifier_entry(godot::String const& identifier, godot::Variant const& entry);
- godot::Error _parse_region_entry(godot::String const& identifier, godot::Variant const& entry);
- godot::Error _parse_terrain_entry(godot::String const& identifier, godot::Variant const& entry, godot::String const& terrain_texture_dir_path);
- godot::Error _parse_good_entry(godot::String const& identifier, godot::Variant const& entry);
-
- godot::Error _load_province_identifier_file(godot::String const& file_path);
- godot::Error _load_water_province_file(godot::String const& file_path);
- godot::Error _load_region_file(godot::String const& file_path);
- godot::Error _load_terrain_variants(godot::String const& terrain_identifiers_path, godot::String const& terrain_texture_dir_path);
godot::Error _generate_terrain_texture_array();
godot::Error _load_map_images(godot::String const& province_image_path, godot::String const& terrain_image_path, bool flip_vertical = false);
- godot::Error _load_goods(godot::String const& defines_path, godot::String const& icons_dir_path);
- godot::Error _load_province_identifier_file_compatibility_mode(godot::String const& file_path);
godot::Error _load_terrain_variants_compatibility_mode(godot::String const& terrain_image_path, godot::String const& terrain_texturesheet_path);
- /* Hardcoded data for defining things for which parsing from files has
- * not been implemented, currently mapmodes and building types.
- */
- godot::Error _load_hardcoded_defines();
-
/* Generate the province_colour_texture from the current mapmode.
*/
godot::Error _update_colour_image();
@@ -83,25 +72,12 @@ namespace OpenVic {
static void setup_logger();
- static godot::StringName const& get_province_identifier_file_key();
- static godot::StringName const& get_water_province_file_key();
- static godot::StringName const& get_region_file_key();
- static godot::StringName const& get_terrain_variant_file_key();
- static godot::StringName const& get_terrain_texture_dir_key();
- static godot::StringName const& get_province_image_file_key();
- static godot::StringName const& get_terrain_image_file_key();
- static godot::StringName const& get_goods_file_key();
- static godot::StringName const& get_good_icons_dir_key();
-
- /* Load the game's defines from the filepaths listed as Strings
- * in a Dictionary, using the StringNames above as keys.
- */
- godot::Error load_defines(godot::Dictionary const& file_dict);
-
/* Load the game's defines in compatiblity mode from the filepath
* pointing to the defines folder.
*/
- godot::Error load_defines_compatibility_mode(godot::String const& file_path);
+ godot::Error load_defines_compatibility_mode(godot::PackedStringArray const& file_paths);
+
+ godot::String lookup_file(godot::String const& path) const;
/* Post-load/restart game setup - reset the game to post-load state
* and (re)generate starting data, e.g. buildings.
diff --git a/extension/src/openvic-extension/LoadGameCompatibility.cpp b/extension/src/openvic-extension/LoadGameCompatibility.cpp
new file mode 100644
index 0000000..e8e3314
--- /dev/null
+++ b/extension/src/openvic-extension/LoadGameCompatibility.cpp
@@ -0,0 +1,110 @@
+#include "GameSingleton.hpp"
+
+#include <godot_cpp/classes/file_access.hpp>
+#include <godot_cpp/variant/utility_functions.hpp>
+
+#include <openvic-simulation/utility/BMP.hpp>
+
+#include "openvic-extension/Utilities.hpp"
+
+using namespace godot;
+using namespace OpenVic;
+
+Error GameSingleton::_load_terrain_variants_compatibility_mode(String const& terrain_image_path, String const& terrain_texturesheet_path) {
+ // Read BMP's palette to determine terrain variant colours which texture they're associated with
+ BMP bmp;
+ if (!(bmp.open(godot_to_std_string(terrain_image_path).c_str()) && bmp.read_header() && bmp.read_palette())) {
+ UtilityFunctions::push_error("Failed to read BMP palette from compatibility mode terrain image: ", terrain_image_path);
+ return FAILED;
+ }
+ std::vector<colour_t> const& palette = bmp.get_palette();
+ static constexpr int32_t SHEET_DIMS = 8, PALETTE_SIZE = SHEET_DIMS * SHEET_DIMS;
+ if (palette.size() == 0 || palette.size() < PALETTE_SIZE) {
+ UtilityFunctions::push_error("Invalid BMP palette size for terrain image: ", static_cast<uint64_t>(palette.size()), " (expected ", PALETTE_SIZE, ")");
+ return FAILED;
+ }
+
+ // Load the terrain texture sheet and prepare to slice it up
+ Ref<Image> terrain_sheet = load_godot_image(terrain_texturesheet_path);
+ if (terrain_sheet.is_null()) {
+ UtilityFunctions::push_error("Failed to load terrain texture sheet: ", terrain_texturesheet_path);
+ return FAILED;
+ }
+ terrain_sheet->flip_y();
+ const int32_t sheet_width = terrain_sheet->get_width(), sheet_height = terrain_sheet->get_height();
+ if (sheet_width < 1 || sheet_width % SHEET_DIMS != 0 || sheet_width != sheet_height) {
+ UtilityFunctions::push_error("Invalid terrain texture sheet dims: ", sheet_width, "x", sheet_height, " (must be square with dims positive multiples of ", SHEET_DIMS, ")");
+ return FAILED;
+ }
+ const int32_t slice_size = sheet_width / SHEET_DIMS;
+
+ {
+ static constexpr colour_t TERRAIN_WATER_INDEX_COLOUR = 0xFFFFFF;
+ Ref<Image> water_image = Image::create(slice_size, slice_size, false, terrain_sheet->get_format());
+ ERR_FAIL_NULL_V_EDMSG(water_image, FAILED, "Failed to create water terrain image");
+ water_image->fill({ 0.1f, 0.1f, 0.5f });
+ terrain_variants.add_item({ "terrain_water", TERRAIN_WATER_INDEX_COLOUR, water_image });
+ }
+ Error err = OK;
+ for (int32_t idx = 0; idx < PALETTE_SIZE; ++idx) {
+ const Rect2i slice { (idx % SHEET_DIMS) * slice_size, (7 - (idx / SHEET_DIMS)) * slice_size, slice_size, slice_size };
+ const Ref<Image> terrain_image = terrain_sheet->get_region(slice);
+ if (terrain_image.is_null() || terrain_image->is_empty()) {
+ UtilityFunctions::push_error("Failed to extract terrain texture slice ", slice, " from ", terrain_texturesheet_path);
+ err = FAILED;
+ continue;
+ }
+ if (!terrain_variants.add_item({ "terrain_" + std::to_string(idx), palette[idx], terrain_image })) err = FAILED;
+ }
+ terrain_variants.lock();
+ if (_generate_terrain_texture_array() != OK) return FAILED;
+ return err;
+}
+
+Error GameSingleton::load_defines_compatibility_mode(PackedStringArray const& file_paths) {
+ static const fs::path province_image_file = "map/provinces.bmp";
+ static const fs::path terrain_image_file = "map/terrain.bmp";
+ static const fs::path terrain_texture_file = "map/terrain/texturesheet.tga";
+
+ Dataloader::path_vector_t roots;
+ for (String const& path : file_paths) {
+ roots.push_back(godot_to_std_string(path));
+ }
+
+ Error err = OK;
+
+ if (!dataloader.set_roots(roots)) {
+ Logger::error("Failed to set dataloader roots!");
+ err = FAILED;
+ }
+
+ if (!dataloader.load_defines(game_manager)) {
+ UtilityFunctions::push_error("Failed to load defines!");
+ err = FAILED;
+ }
+
+ game_manager.map.lock_regions();
+ if (_load_terrain_variants_compatibility_mode(
+ std_to_godot_string(dataloader.lookup_file(terrain_image_file).string()),
+ std_to_godot_string(dataloader.lookup_file(terrain_texture_file).string())
+ ) != OK) {
+ UtilityFunctions::push_error("Failed to load terrain variants!");
+ err = FAILED;
+ }
+ if (_load_map_images(
+ std_to_godot_string(dataloader.lookup_file(province_image_file).string()),
+ std_to_godot_string(dataloader.lookup_file(terrain_image_file).string()),
+ true) != OK) {
+ UtilityFunctions::push_error("Failed to load map images!");
+ err = FAILED;
+ }
+ if (!game_manager.load_hardcoded_defines()) {
+ UtilityFunctions::push_error("Failed to hardcoded defines!");
+ err = FAILED;
+ }
+ return err;
+}
+
+String GameSingleton::lookup_file(String const& path) const {
+ return std_to_godot_string(dataloader.lookup_file(godot_to_std_string(path)).string());
+}
diff --git a/extension/src/openvic-extension/LoadGameOpenVic.cpp b/extension/src/openvic-extension/LoadGameOpenVic.cpp
new file mode 100644
index 0000000..87c66da
--- /dev/null
+++ b/extension/src/openvic-extension/LoadGameOpenVic.cpp
@@ -0,0 +1,132 @@
+#include "GameSingleton.hpp"
+
+#include <godot_cpp/classes/file_access.hpp>
+#include <godot_cpp/classes/json.hpp>
+#include <godot_cpp/variant/utility_functions.hpp>
+
+#include "openvic-extension/Utilities.hpp"
+
+using namespace godot;
+using namespace OpenVic;
+
+Error GameSingleton::_generate_terrain_texture_array() {
+ Error err = OK;
+ if (terrain_variants.size() == 0) {
+ UtilityFunctions::push_error("Failed to load terrain textures!");
+ return FAILED;
+ }
+ // TerrainVariant count is limited by the data type representing it in the map image
+ if (terrain_variants.size() > TerrainVariant::MAX_TERRIN_VARIANT_COUNT) {
+ UtilityFunctions::push_error("Too many terrain textures - all after the first ",
+ static_cast<uint64_t>(TerrainVariant::MAX_TERRIN_VARIANT_COUNT), " will be ignored");
+ err = FAILED;
+ }
+
+ Array terrain_images;
+ for (size_t i = 0; i < terrain_variants.size() && i < TerrainVariant::MAX_TERRIN_VARIANT_COUNT; ++i) {
+ TerrainVariant const& var = *terrain_variants.get_item_by_index(i);
+ terrain_variant_map[var.get_colour()] = i;
+ terrain_images.append(var.get_image());
+ }
+
+ terrain_texture.instantiate();
+ if (terrain_texture->create_from_images(terrain_images) != OK) {
+ UtilityFunctions::push_error("Failed to create terrain texture array!");
+ return FAILED;
+ }
+ return err;
+}
+
+Error GameSingleton::_load_map_images(String const& province_image_path, String const& terrain_image_path, bool flip_vertical) {
+ if (province_shape_texture.is_valid()) {
+ UtilityFunctions::push_error("Map images have already been loaded, cannot load: ", province_image_path, " and ", terrain_image_path);
+ return FAILED;
+ }
+
+ // Load images
+ Ref<Image> province_image = load_godot_image(province_image_path);
+ if (province_image.is_null()) {
+ UtilityFunctions::push_error("Failed to load province image: ", province_image_path);
+ return FAILED;
+ }
+ Ref<Image> terrain_image = load_godot_image(terrain_image_path);
+ if (terrain_image.is_null()) {
+ UtilityFunctions::push_error("Failed to load terrain image: ", terrain_image_path);
+ return FAILED;
+ }
+
+ if (flip_vertical) {
+ province_image->flip_y();
+ terrain_image->flip_y();
+ }
+
+ // Validate dimensions and format
+ Error err = OK;
+ const Vector2i province_dims = province_image->get_size(), terrain_dims = terrain_image->get_size();
+ if (province_dims.x < 1 || province_dims.y < 1) {
+ UtilityFunctions::push_error("Invalid dimensions (", province_dims.x, "x", province_dims.y, ") for province image: ", province_image_path);
+ err = FAILED;
+ }
+ if (province_dims != terrain_dims) {
+ UtilityFunctions::push_error("Invalid dimensions (", terrain_dims.x, "x", terrain_dims.y, ") for terrain image: ",
+ terrain_image_path, " (must match province image: (", province_dims.x, "x", province_dims.x, "))");
+ err = FAILED;
+ }
+ static constexpr Image::Format expected_format = Image::FORMAT_RGB8;
+ if (province_image->get_format() == Image::FORMAT_RGBA8) province_image->convert(expected_format);
+ if (terrain_image->get_format() == Image::FORMAT_RGBA8) terrain_image->convert(expected_format);
+ if (province_image->get_format() != expected_format) {
+ UtilityFunctions::push_error("Invalid format (", province_image->get_format(), ", should be ", expected_format, ") for province image: ", province_image_path);
+ err = FAILED;
+ }
+ if (terrain_image->get_format() != expected_format) {
+ UtilityFunctions::push_error("Invalid format (", terrain_image->get_format(), ", should be ", expected_format, ") for terrain image: ", terrain_image_path);
+ err = FAILED;
+ }
+ if (err != OK) return err;
+
+ // Generate interleaved province and terrain ID image
+ if (!game_manager.map.generate_province_shape_image(province_dims.x, province_dims.y,
+ province_image->get_data().ptr(), terrain_image->get_data().ptr(), terrain_variant_map,
+ false /* <-- whether to print detailed map errors or not (specific missing/unrecognised colours) */
+ )) err = FAILED;
+
+ static constexpr int32_t GPU_DIM_LIMIT = 0x3FFF;
+ // For each dimension of the image, this finds the small number of equal subdivisions required get the individual texture dims under GPU_DIM_LIMIT
+ for (int i = 0; i < 2; ++i)
+ for (image_subdivisions[i] = 1; province_dims[i] / image_subdivisions[i] > GPU_DIM_LIMIT ||
+ province_dims[i] % image_subdivisions[i] != 0; ++image_subdivisions[i]);
+
+ Map::shape_pixel_t const* province_shape_data = game_manager.map.get_province_shape_image().data();
+ const Vector2i divided_dims = province_dims / image_subdivisions;
+ Array province_shape_images;
+ province_shape_images.resize(image_subdivisions.x * image_subdivisions.y);
+ for (int32_t v = 0; v < image_subdivisions.y; ++v) {
+ for (int32_t u = 0; u < image_subdivisions.x; ++u) {
+ PackedByteArray index_data_array;
+ index_data_array.resize(divided_dims.x * divided_dims.y * sizeof(Map::shape_pixel_t));
+
+ for (int32_t y = 0; y < divided_dims.y; ++y)
+ memcpy(index_data_array.ptrw() + y * divided_dims.x * sizeof(Map::shape_pixel_t),
+ province_shape_data + (v * divided_dims.y + y) * province_dims.x + u * divided_dims.x,
+ divided_dims.x * sizeof(Map::shape_pixel_t));
+
+ const Ref<Image> province_shape_subimage = Image::create_from_data(divided_dims.x, divided_dims.y, false, Image::FORMAT_RGB8, index_data_array);
+ if (province_shape_subimage.is_null()) {
+ UtilityFunctions::push_error("Failed to create province shape image (", u, ", ", v, ")");
+ err = FAILED;
+ }
+ province_shape_images[u + v * image_subdivisions.x] = province_shape_subimage;
+ }
+ }
+
+ province_shape_texture.instantiate();
+ if (province_shape_texture->create_from_images(province_shape_images) != OK) {
+ UtilityFunctions::push_error("Failed to create terrain texture array!");
+ err = FAILED;
+ }
+
+ if (_update_colour_image() != OK) err = FAILED;
+
+ return err;
+}
diff --git a/extension/src/LoadLocalisation.cpp b/extension/src/openvic-extension/LoadLocalisation.cpp
index dc7702c..dc7702c 100644
--- a/extension/src/LoadLocalisation.cpp
+++ b/extension/src/openvic-extension/LoadLocalisation.cpp
diff --git a/extension/src/LoadLocalisation.hpp b/extension/src/openvic-extension/LoadLocalisation.hpp
index 04ec5c7..04ec5c7 100644
--- a/extension/src/LoadLocalisation.hpp
+++ b/extension/src/openvic-extension/LoadLocalisation.hpp
diff --git a/extension/src/MapMesh.cpp b/extension/src/openvic-extension/MapMesh.cpp
index 269360a..269360a 100644
--- a/extension/src/MapMesh.cpp
+++ b/extension/src/openvic-extension/MapMesh.cpp
diff --git a/extension/src/MapMesh.hpp b/extension/src/openvic-extension/MapMesh.hpp
index 38b208c..38b208c 100644
--- a/extension/src/MapMesh.hpp
+++ b/extension/src/openvic-extension/MapMesh.hpp
diff --git a/extension/src/Utilities.cpp b/extension/src/openvic-extension/Utilities.cpp
index f09eae0..4ca6855 100644
--- a/extension/src/Utilities.cpp
+++ b/extension/src/openvic-extension/Utilities.cpp
@@ -19,7 +19,7 @@ Ref<Image> OpenVic::load_godot_image(String const& path) {
// Get the polar coordinates of a pixel relative to the center
static Vector2 getPolar(Vector2 UVin, Vector2 center) {
- Vector2 relcoord = (UVin-center);
+ Vector2 relcoord = (UVin - center);
float dist = relcoord.length();
float theta = std::numbers::pi / 2 + atan2(relcoord.y, relcoord.x);
if (theta < 0.0f) theta += std::numbers::pi * 2;
@@ -27,11 +27,11 @@ static Vector2 getPolar(Vector2 UVin, Vector2 center) {
}
// From thebookofshaders, returns a gradient falloff
-static inline float parabola(float base, float x, float k){
+static inline float parabola(float base, float x, float k) {
return powf(base * x * (1.0 - x), k);
}
-static inline float parabola_shadow(float base, float x){
+static inline float parabola_shadow(float base, float x) {
return base * x * x;
}
@@ -57,9 +57,9 @@ static Color pie_chart_fragment(Vector2 UV, float radius, Array const& stopAngle
return { trim_colour, 1.0 };
}
// Interior
- else if (dist <= radius-trim_size) {
+ else if (dist <= radius - trim_size) {
Color col { 1.0f, 0.0f, 0.0f };
- for (int i = 0; i < stopAngles.size(); i++){
+ for (int i = 0; i < stopAngles.size(); i++) {
if (theta <= float(stopAngles[i])) {
col = colours[i];
break;
@@ -73,7 +73,7 @@ static Color pie_chart_fragment(Vector2 UV, float radius, Array const& stopAngle
return { trim_colour, 1.0 };
}
// Outside the circle
- else{
+ else {
return { 0.1, 0.1, 0.1, shadow_gradient };
}
}
diff --git a/extension/src/Utilities.hpp b/extension/src/openvic-extension/Utilities.hpp
index e8796e9..32e7cb5 100644
--- a/extension/src/Utilities.hpp
+++ b/extension/src/openvic-extension/Utilities.hpp
@@ -2,9 +2,9 @@
#include <godot_cpp/classes/image.hpp>
-#include "openvic/Types.hpp"
+#include <openvic-simulation/types/Colour.hpp>
-#define ERR(x) ((x) == SUCCESS ? OK : FAILED)
+#define ERR(x) ((x) ? OK : FAILED)
namespace OpenVic {
diff --git a/extension/src/register_types.cpp b/extension/src/openvic-extension/register_types.cpp
index 92c25a4..273bb85 100644
--- a/extension/src/register_types.cpp
+++ b/extension/src/openvic-extension/register_types.cpp
@@ -1,11 +1,11 @@
-#include "register_types.h"
+#include "register_types.hpp"
#include <godot_cpp/classes/engine.hpp>
-#include "Checksum.hpp"
-#include "GameSingleton.hpp"
-#include "LoadLocalisation.hpp"
-#include "MapMesh.hpp"
+#include "openvic-extension/Checksum.hpp"
+#include "openvic-extension/GameSingleton.hpp"
+#include "openvic-extension/LoadLocalisation.hpp"
+#include "openvic-extension/MapMesh.hpp"
using namespace godot;
using namespace OpenVic;
diff --git a/extension/src/register_types.h b/extension/src/openvic-extension/register_types.hpp
index dd24689..dd24689 100644
--- a/extension/src/register_types.h
+++ b/extension/src/openvic-extension/register_types.hpp
diff --git a/game/localisation/en_GB/mapmodes.csv b/game/localisation/en_GB/mapmodes.csv
index 8fa5798..bcb466f 100644
--- a/game/localisation/en_GB/mapmodes.csv
+++ b/game/localisation/en_GB/mapmodes.csv
@@ -8,3 +8,4 @@ mapmode_rgo;RGO
mapmode_infrastructure;Infrastructure
mapmode_population;Population Density
mapmode_culture;Nationality
+mapmode_religion;Religion
diff --git a/game/project.godot b/game/project.godot
index f8bd428..ead3c6b 100644
--- a/game/project.godot
+++ b/game/project.godot
@@ -15,17 +15,19 @@ config/description="A faithful recreation of Victoria 2: Heart of Darkness with
run/main_scene="res://src/Game/GameStart.tscn"
config/use_custom_user_dir=true
config/features=PackedStringArray("4.1", "Forward Plus")
-boot_splash/bg_color=Color(0.380392, 0.145098, 0.14902, 1)
+boot_splash/bg_color=Color(0, 0, 0, 0)
+boot_splash/show_image=false
boot_splash/image="res://splash_assets/splash_image.png"
config/icon="res://icon.svg"
config/project_settings_override.template="user://settings.cfg"
[autoload]
+Resolution="*res://src/Game/Autoload/Resolution.gd"
ArgumentParser="*res://src/Game/Autoload/Argument/ArgumentParser.tscn"
+WindowOverride="*res://src/Game/Autoload/WindowOverride.gd"
Events="*res://src/Game/Autoload/Events.gd"
GameLoader="*res://src/Game/Autoload/GameLoader.gd"
-Resolution="*res://src/Game/Autoload/Resolution.gd"
SoundManager="*res://src/Game/Autoload/SoundManager.gd"
MusicConductor="*res://src/Game/MusicConductor/MusicConductor.tscn"
Keychain="*res://addons/keychain/Keychain.gd"
@@ -36,10 +38,15 @@ SaveManager="*res://src/Game/Autoload/SaveManager.gd"
window/size/viewport_width=1280
window/size/viewport_height=720
-window/size/mode=3
+window/size/mode=1
window/size/resizable=false
+window/size/borderless=true
+window/size/transparent=true
+window/size/window_width_override=1
+window/size/window_height_override=1
window/stretch/mode="canvas_items"
window/stretch/aspect="ignore"
+window/per_pixel_transparency/allowed=true
[editor_plugins]
diff --git a/game/src/Game/Autoload/Argument/ArgumentParser.gd b/game/src/Game/Autoload/Argument/ArgumentParser.gd
index b463c74..b012215 100644
--- a/game/src/Game/Autoload/Argument/ArgumentParser.gd
+++ b/game/src/Game/Autoload/Argument/ArgumentParser.gd
@@ -309,10 +309,8 @@ Options:
("Type: %s - Default Value: %s" % [option.get_type_string(), option.default_value]).rpad(45),
option.description
])
+
func _ready():
if Engine.is_editor_hint(): return
_set_argument_setting()
GameDebug._singleton = GameDebug.new()
- if get_argument(&"help"):
- _print_help()
- get_tree().quit()
diff --git a/game/src/Game/Autoload/GameLoader.gd b/game/src/Game/Autoload/GameLoader.gd
index 1720e3c..8c14c7e 100644
--- a/game/src/Game/Autoload/GameLoader.gd
+++ b/game/src/Game/Autoload/GameLoader.gd
@@ -1,17 +1,5 @@
extends Node
-var define_filepaths_dict : Dictionary = {
- GameSingleton.get_province_identifier_file_key(): "res://common/map/provinces.json",
- GameSingleton.get_water_province_file_key(): "res://common/map/water.json",
- GameSingleton.get_region_file_key(): "res://common/map/regions.json",
- GameSingleton.get_terrain_variant_file_key(): "res://common/map/terrain.json",
- GameSingleton.get_terrain_texture_dir_key(): "res://art/terrain/",
- GameSingleton.get_province_image_file_key(): "res://common/map/provinces.png",
- GameSingleton.get_terrain_image_file_key(): "res://common/map/terrain.png",
- GameSingleton.get_goods_file_key(): "res://common/goods.json",
- GameSingleton.get_good_icons_dir_key(): "res://art/economy/goods"
-}
-
var ShaderManager : ShaderManagerClass
func _init():
diff --git a/game/src/Game/Autoload/WindowOverride.gd b/game/src/Game/Autoload/WindowOverride.gd
new file mode 100644
index 0000000..837570e
--- /dev/null
+++ b/game/src/Game/Autoload/WindowOverride.gd
@@ -0,0 +1,27 @@
+extends Node
+
+const VideoOptions = preload("res://src/Game/Menu/OptionMenu/VideoTab.tscn")
+
+func _init():
+ var window_id := DisplayServer.get_window_list()[0]
+ DisplayServer.window_set_size(Vector2(1280.0, 720.0), window_id)
+
+func _ready():
+ if ArgumentParser.get_argument(&"help"): return
+ _on_SceneTree_idle()
+ # Hack to ensure Video Options load
+ var video := VideoOptions.instantiate()
+ video.visible = false
+ add_child(video)
+ video.queue_free()
+
+func _on_SceneTree_idle():
+ var window := get_window()
+ window.set_mode(Window.MODE_FULLSCREEN)
+ await get_tree().process_frame
+ window.transparent = false
+ window.borderless = false
+ var screen_pos := DisplayServer.screen_get_position(window.current_screen)
+ var screen_size := DisplayServer.screen_get_size(window.current_screen)
+ window.position = screen_pos + (screen_size - window.size) / 2
+ ProjectSettings.set_setting.call_deferred("display/window/per_pixel_transparency/allowed", false)
diff --git a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd
index 350c1a8..6cdbf28 100644
--- a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd
+++ b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd
@@ -11,7 +11,7 @@ signal zoom_out_button_pressed
var _mapmode_button_group : ButtonGroup
# REQUIREMENTS:
-# * UI-550, UI-552, UI-554, UI-561, UI-562
+# * UI-550, UI-552, UI-554, UI-561, UI-562, UI-563
func _add_mapmode_button(identifier : String) -> void:
var button := Button.new()
button.text = identifier
@@ -37,7 +37,7 @@ func _on_game_session_menu_button_pressed() -> void:
# REQUIREMENTS:
# * SS-76
-# * UIFUN-129, UIFUN-131, UIFUN-133, UIFUN-140, UIFUN-141
+# * UIFUN-129, UIFUN-131, UIFUN-133, UIFUN-140, UIFUN-141, UIFUN-142
func _mapmode_pressed(button : BaseButton) -> void:
GameSingleton.set_mapmode(button.tooltip_text)
diff --git a/game/src/Game/GameSession/ProvinceOverviewPanel/ProvinceOverviewPanel.tscn b/game/src/Game/GameSession/ProvinceOverviewPanel/ProvinceOverviewPanel.tscn
index 7e49ac8..7a982e9 100644
--- a/game/src/Game/GameSession/ProvinceOverviewPanel/ProvinceOverviewPanel.tscn
+++ b/game/src/Game/GameSession/ProvinceOverviewPanel/ProvinceOverviewPanel.tscn
@@ -93,15 +93,18 @@ layout_mode = 2
mouse_filter = 1
[node name="PopStats" type="HBoxContainer" parent="PanelList/InteractList"]
+editor_description = "UI-124"
layout_mode = 2
[node name="PopTypeChart" parent="PanelList/InteractList/PopStats" instance=ExtResource("2_3oytt")]
+editor_description = "UI-125"
layout_mode = 2
[node name="PopIdeologyChart" parent="PanelList/InteractList/PopStats" instance=ExtResource("2_3oytt")]
layout_mode = 2
[node name="PopCultureChart" parent="PanelList/InteractList/PopStats" instance=ExtResource("2_3oytt")]
+editor_description = "UI-127"
layout_mode = 2
[node name="HSeparator3" type="HSeparator" parent="PanelList/InteractList"]
diff --git a/game/src/Game/GameStart.gd b/game/src/Game/GameStart.gd
index fa7568b..422a42a 100644
--- a/game/src/Game/GameStart.gd
+++ b/game/src/Game/GameStart.gd
@@ -7,6 +7,15 @@ const SoundTabScene = preload("res://src/Game/Menu/OptionMenu/SoundTab.tscn")
@export var loading_screen : LoadingScreen
func _ready() -> void:
+ if ArgumentParser.get_argument(&"help"):
+ ArgumentParser._print_help()
+ # For some reason this doesn't get freed properly
+ # Godot will always quit before it frees the active StreamPlayback resource
+ # This hack fixes that
+ MusicConductor.queue_free()
+ get_tree().quit()
+ return
+
# Hack to ensure Sound Options load
var sound_tab := SoundTabScene.instantiate()
sound_tab.visible = false
@@ -16,39 +25,42 @@ func _ready() -> void:
loading_screen.start_loading_screen(_initialize_game)
-# REQUIREMENTS
-# * FS-333, FS-334, FS-335, FS-341
-func _initialize_game() -> void:
- GameSingleton.setup_logger()
- loading_screen.try_update_loading_screen(5)
-
+func _load_compatibility_mode():
# Set this to your Vic2 install dir or a mod's dir to enable compatibility mode
# (this won't work for mods which rely on vanilla map assets, copy missing assets
# into the mod's dir for a temporary fix)
# Usage: OpenVic --compatibility-mode <path>
- var compatibility_mode_path : String = ArgumentParser.get_argument(&"compatibility-mode")
+ var compatibility_mode_path : String = ArgumentParser.get_argument(&"compatibility-mode", "")
+
+ if not compatibility_mode_path:
+ # TODO - non-Windows default paths
+ const default_path : String = "C:/Program Files (x86)/Steam/steamapps/common/Victoria 2"
+ compatibility_mode_path = default_path
+
+ var compatibility_mode_paths : PackedStringArray = [compatibility_mode_path]
+ # Example for adding mod paths
+ #compatibility_mode_paths.push_back("C:/Program Files (x86)/Steam/steamapps/common/Victoria 2/mod/TGC")
+
+ if GameSingleton.load_defines_compatibility_mode(compatibility_mode_paths) != OK:
+ push_error("Errors loading game defines!")
+
+# REQUIREMENTS
+# * FS-333, FS-334, FS-335, FS-341
+func _initialize_game() -> void:
var start := Time.get_ticks_usec()
+ loading_screen.try_update_loading_screen(0)
+ GameSingleton.setup_logger()
- loading_screen.try_update_loading_screen(15)
- loading_screen.try_update_loading_screen(25)
Localisation.initialize()
- loading_screen.try_update_loading_screen(45)
- loading_screen.try_update_loading_screen(50, true)
-
- # TODO: Loading takes way too long to keep the LoadingScreen at 50%
- # Should either split this up or seperately multithread the compatibility mode loader
- # Or both and emit a signal that allows us to add percentages to the LoadingScreen
- if compatibility_mode_path:
- if GameSingleton.load_defines_compatibility_mode(compatibility_mode_path) != OK:
- push_error("Errors loading game defines!")
- else:
- GameLoader.define_filepaths_dict.make_read_only()
- if GameSingleton.load_defines(GameLoader.define_filepaths_dict) != OK:
- push_error("Errors loading game defines!")
+ loading_screen.try_update_loading_screen(15, true)
+
+ _load_compatibility_mode()
+ loading_screen.try_update_loading_screen(75, true)
loading_screen.try_update_loading_screen(100)
+
var end := Time.get_ticks_usec()
print("Loading took ", float(end - start) / 1000000, " seconds")
diff --git a/game/src/Game/LoadingScreen.tscn b/game/src/Game/LoadingScreen.tscn
index 5ae1cb9..01b6856 100644
--- a/game/src/Game/LoadingScreen.tscn
+++ b/game/src/Game/LoadingScreen.tscn
@@ -59,6 +59,7 @@ _data = {
}
[node name="LoadingScreen" type="Control" node_paths=PackedStringArray("progress_bar", "quote_label", "animation_player")]
+editor_description = "UI-24"
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0