From 21aeaadf332d1a0d874f2c3850944fbdc6e64ff1 Mon Sep 17 00:00:00 2001 From: Hop311 Date: Fri, 7 Apr 2023 15:29:09 +0100 Subject: Logo on Mainmenu + icon imports + whitespace cleanup (#82) * Whitespace cleanup * Icon import files * Logo on main menu. --- docs/general-program-architecture.md | 4 +-- docs/simulation/goods.md | 2 +- docs/simulation/ideologies.md | 4 +-- docs/simulation/provinces.md | 16 +++++----- docs/styleguide-cpp.md | 6 ++-- game/art/economy/goods/Aeroplanes.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Ammunition.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Artillery.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Automobiles.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/CannedFood.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Cattle.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Cement.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/ClipperConvoys.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Coal.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Coffee.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Cotton.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Dye.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/ElectricGear.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Explosives.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Fabric.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Fertilizer.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Fish.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Fruit.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Fuel.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Furniture.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Glass.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Grain.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Iron.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Liquor.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Lumber.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/LuxuryClothes.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/LuxuryFurniture.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/MachineParts.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Oil.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Opium.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Paper.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/PreciousMetal.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Radios.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/RegularClothes.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Rubber.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Silk.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/SmallArms.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/SteamerConvoys.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Steel.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Sulphur.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Tanks.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Tea.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Telephones.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Timber.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Tobacco.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/TropicalWood.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Wine.png.import | 34 +++++++++++++++++++++ game/art/economy/goods/Wool.png.import | 34 +++++++++++++++++++++ .../army/Army Decision Making.png.import | 34 +++++++++++++++++++++ .../technology/army/Army NCO Training.png.import | 34 +++++++++++++++++++++ .../army/Army Professionalism.png.import | 34 +++++++++++++++++++++ .../army/Army Risk Management.png.import | 34 +++++++++++++++++++++ .../technology/army/Bolt-action Rifle.png.import | 34 +++++++++++++++++++++ .../army/Breech-Loaded Rifles.png.import | 34 +++++++++++++++++++++ .../army/Bronze Muzzle-loaded Artillery.png.import | 34 +++++++++++++++++++++ .../technology/army/Deep Defense System.png.import | 34 +++++++++++++++++++++ .../technology/army/Flintlock Rifles.png.import | 34 +++++++++++++++++++++ .../army/Indirect Artillery Fire.png.import | 34 +++++++++++++++++++++ game/art/technology/army/Infiltration.png.import | 34 +++++++++++++++++++++ .../army/Iron Breech-Loaded Artillery.png.import | 34 +++++++++++++++++++++ .../army/Iron Muzzle-Loaded Artillery.png.import | 34 +++++++++++++++++++++ game/art/technology/army/Machine Gun.png.import | 34 +++++++++++++++++++++ .../army/Military Directionism.png.import | 34 +++++++++++++++++++++ .../technology/army/Military Logistics.png.import | 34 +++++++++++++++++++++ game/art/technology/army/Military Plans.png.import | 34 +++++++++++++++++++++ .../army/Military Staff System.png.import | 34 +++++++++++++++++++++ .../technology/army/Military Statistics.png.import | 34 +++++++++++++++++++++ .../army/Muzzle-loaded Rifles.png.import | 34 +++++++++++++++++++++ .../army/Point Defense System.png.import | 34 +++++++++++++++++++++ .../army/Post-Napoleonic Thought.png.import | 34 +++++++++++++++++++++ .../army/Steel Breech-Loaded Artillery.png.import | 34 +++++++++++++++++++++ .../technology/army/Strategic Mobility.png.import | 34 +++++++++++++++++++++ .../army/The Command Principle.png.import | 34 +++++++++++++++++++++ game/art/units/Airplane.png.import | 34 +++++++++++++++++++++ game/art/units/Armor.png.import | 34 +++++++++++++++++++++ game/art/units/Artillery.png.import | 34 +++++++++++++++++++++ game/art/units/Battleship.png.import | 34 +++++++++++++++++++++ game/art/units/Cavalry.png.import | 34 +++++++++++++++++++++ game/art/units/ClipperTransport.png.import | 34 +++++++++++++++++++++ game/art/units/CommerceRaider.png.import | 34 +++++++++++++++++++++ game/art/units/Cruiser.png.import | 34 +++++++++++++++++++++ game/art/units/Cuirassier.png.import | 34 +++++++++++++++++++++ game/art/units/Dragoon.png.import | 34 +++++++++++++++++++++ game/art/units/Dreadnought.png.import | 34 +++++++++++++++++++++ game/art/units/Engineer.png.import | 34 +++++++++++++++++++++ game/art/units/Frigate.png.import | 34 +++++++++++++++++++++ game/art/units/Guard.png.import | 34 +++++++++++++++++++++ game/art/units/Hussar.png.import | 34 +++++++++++++++++++++ game/art/units/Infantry.png.import | 34 +++++++++++++++++++++ game/art/units/Ironclad.png.import | 34 +++++++++++++++++++++ game/art/units/Irregular.png.import | 34 +++++++++++++++++++++ game/art/units/ManOWar.png.import | 34 +++++++++++++++++++++ game/art/units/Monitor.png.import | 34 +++++++++++++++++++++ game/art/units/SteamerTransport.png.import | 34 +++++++++++++++++++++ game/src/MainMenu/MainMenu.tscn | 16 +++++----- game/src/MusicConductor/MusicConductor.gd | 2 +- game/theme/assets/OpenVicFINALREALTRANS.png | Bin 0 -> 57587 bytes game/theme/assets/OpenVicFINALREALTRANS.png.import | 34 +++++++++++++++++++++ game/theme/main_menu.tres | 2 -- 104 files changed, 3255 insertions(+), 27 deletions(-) create mode 100644 game/art/economy/goods/Aeroplanes.png.import create mode 100644 game/art/economy/goods/Ammunition.png.import create mode 100644 game/art/economy/goods/Artillery.png.import create mode 100644 game/art/economy/goods/Automobiles.png.import create mode 100644 game/art/economy/goods/CannedFood.png.import create mode 100644 game/art/economy/goods/Cattle.png.import create mode 100644 game/art/economy/goods/Cement.png.import create mode 100644 game/art/economy/goods/ClipperConvoys.png.import create mode 100644 game/art/economy/goods/Coal.png.import create mode 100644 game/art/economy/goods/Coffee.png.import create mode 100644 game/art/economy/goods/Cotton.png.import create mode 100644 game/art/economy/goods/Dye.png.import create mode 100644 game/art/economy/goods/ElectricGear.png.import create mode 100644 game/art/economy/goods/Explosives.png.import create mode 100644 game/art/economy/goods/Fabric.png.import create mode 100644 game/art/economy/goods/Fertilizer.png.import create mode 100644 game/art/economy/goods/Fish.png.import create mode 100644 game/art/economy/goods/Fruit.png.import create mode 100644 game/art/economy/goods/Fuel.png.import create mode 100644 game/art/economy/goods/Furniture.png.import create mode 100644 game/art/economy/goods/Glass.png.import create mode 100644 game/art/economy/goods/Grain.png.import create mode 100644 game/art/economy/goods/Iron.png.import create mode 100644 game/art/economy/goods/Liquor.png.import create mode 100644 game/art/economy/goods/Lumber.png.import create mode 100644 game/art/economy/goods/LuxuryClothes.png.import create mode 100644 game/art/economy/goods/LuxuryFurniture.png.import create mode 100644 game/art/economy/goods/MachineParts.png.import create mode 100644 game/art/economy/goods/Oil.png.import create mode 100644 game/art/economy/goods/Opium.png.import create mode 100644 game/art/economy/goods/Paper.png.import create mode 100644 game/art/economy/goods/PreciousMetal.png.import create mode 100644 game/art/economy/goods/Radios.png.import create mode 100644 game/art/economy/goods/RegularClothes.png.import create mode 100644 game/art/economy/goods/Rubber.png.import create mode 100644 game/art/economy/goods/Silk.png.import create mode 100644 game/art/economy/goods/SmallArms.png.import create mode 100644 game/art/economy/goods/SteamerConvoys.png.import create mode 100644 game/art/economy/goods/Steel.png.import create mode 100644 game/art/economy/goods/Sulphur.png.import create mode 100644 game/art/economy/goods/Tanks.png.import create mode 100644 game/art/economy/goods/Tea.png.import create mode 100644 game/art/economy/goods/Telephones.png.import create mode 100644 game/art/economy/goods/Timber.png.import create mode 100644 game/art/economy/goods/Tobacco.png.import create mode 100644 game/art/economy/goods/TropicalWood.png.import create mode 100644 game/art/economy/goods/Wine.png.import create mode 100644 game/art/economy/goods/Wool.png.import create mode 100644 game/art/technology/army/Army Decision Making.png.import create mode 100644 game/art/technology/army/Army NCO Training.png.import create mode 100644 game/art/technology/army/Army Professionalism.png.import create mode 100644 game/art/technology/army/Army Risk Management.png.import create mode 100644 game/art/technology/army/Bolt-action Rifle.png.import create mode 100644 game/art/technology/army/Breech-Loaded Rifles.png.import create mode 100644 game/art/technology/army/Bronze Muzzle-loaded Artillery.png.import create mode 100644 game/art/technology/army/Deep Defense System.png.import create mode 100644 game/art/technology/army/Flintlock Rifles.png.import create mode 100644 game/art/technology/army/Indirect Artillery Fire.png.import create mode 100644 game/art/technology/army/Infiltration.png.import create mode 100644 game/art/technology/army/Iron Breech-Loaded Artillery.png.import create mode 100644 game/art/technology/army/Iron Muzzle-Loaded Artillery.png.import create mode 100644 game/art/technology/army/Machine Gun.png.import create mode 100644 game/art/technology/army/Military Directionism.png.import create mode 100644 game/art/technology/army/Military Logistics.png.import create mode 100644 game/art/technology/army/Military Plans.png.import create mode 100644 game/art/technology/army/Military Staff System.png.import create mode 100644 game/art/technology/army/Military Statistics.png.import create mode 100644 game/art/technology/army/Muzzle-loaded Rifles.png.import create mode 100644 game/art/technology/army/Point Defense System.png.import create mode 100644 game/art/technology/army/Post-Napoleonic Thought.png.import create mode 100644 game/art/technology/army/Steel Breech-Loaded Artillery.png.import create mode 100644 game/art/technology/army/Strategic Mobility.png.import create mode 100644 game/art/technology/army/The Command Principle.png.import create mode 100644 game/art/units/Airplane.png.import create mode 100644 game/art/units/Armor.png.import create mode 100644 game/art/units/Artillery.png.import create mode 100644 game/art/units/Battleship.png.import create mode 100644 game/art/units/Cavalry.png.import create mode 100644 game/art/units/ClipperTransport.png.import create mode 100644 game/art/units/CommerceRaider.png.import create mode 100644 game/art/units/Cruiser.png.import create mode 100644 game/art/units/Cuirassier.png.import create mode 100644 game/art/units/Dragoon.png.import create mode 100644 game/art/units/Dreadnought.png.import create mode 100644 game/art/units/Engineer.png.import create mode 100644 game/art/units/Frigate.png.import create mode 100644 game/art/units/Guard.png.import create mode 100644 game/art/units/Hussar.png.import create mode 100644 game/art/units/Infantry.png.import create mode 100644 game/art/units/Ironclad.png.import create mode 100644 game/art/units/Irregular.png.import create mode 100644 game/art/units/ManOWar.png.import create mode 100644 game/art/units/Monitor.png.import create mode 100644 game/art/units/SteamerTransport.png.import create mode 100644 game/theme/assets/OpenVicFINALREALTRANS.png create mode 100644 game/theme/assets/OpenVicFINALREALTRANS.png.import diff --git a/docs/general-program-architecture.md b/docs/general-program-architecture.md index 533a8fa..c37d390 100644 --- a/docs/general-program-architecture.md +++ b/docs/general-program-architecture.md @@ -19,14 +19,14 @@ Player ->> UI: Press "New Game" or
"Load Game" button UI ->> Bridge: Begin new Game Session Bridge ->> Simulation: Start new Game Session Simulation -->> Dataloader: Load previous savegame
(If necessary) -Dataloader -->> Simulation: +Dataloader -->> Simulation: Simulation ->> Bridge: Provide information necessary
for UI and visual elements Bridge ->> UI: Signal that Game Session
is ready for interaction UI ->> Player: Present to Player loop Core Game Loop Player ->> UI: Interact with game controls -UI ->> Bridge: Convey player intent
according to UI
handler functions +UI ->> Bridge: Convey player intent
according to UI
handler functions Bridge ->> Simulation: Relay changes to entities
controlled by the Player Note over Simulation: When unpaused: Simulation ->> Simulation: Advance to next in-game day
according to game speed
and update Simulation state diff --git a/docs/simulation/goods.md b/docs/simulation/goods.md index 15b4864..f8204b0 100644 --- a/docs/simulation/goods.md +++ b/docs/simulation/goods.md @@ -28,7 +28,7 @@ classDiagram Good o-- GoodCategory ``` -## Data +## Data ### Vanilla diff --git a/docs/simulation/ideologies.md b/docs/simulation/ideologies.md index f56cda7..817bdb3 100644 --- a/docs/simulation/ideologies.md +++ b/docs/simulation/ideologies.md @@ -27,7 +27,7 @@ classDiagram ``` -## Data +## Data ### Vanilla @@ -41,7 +41,7 @@ classDiagram |communist|socialist|1865/01/01|False|#960A0A| |fascist|fascist|1905/01/01|False|#3C3C3C| -### John Cena +### John Cena |Identifier|Ideological Group|Earliest Date|Uncivilized Nations|Colour| |--|--|--|--|--| diff --git a/docs/simulation/provinces.md b/docs/simulation/provinces.md index 88eea50..642ff11 100644 --- a/docs/simulation/provinces.md +++ b/docs/simulation/provinces.md @@ -5,16 +5,16 @@ ```mermaid classDiagram class Province { - Int64 id - string provinceName - string tradeGood - Int64 lifeRating - bool hasLegalSlavery + Int64 id + string provinceName + string tradeGood + Int64 lifeRating + bool hasLegalSlavery - Int64 fortLevel - Int64 navalBaseLevel + Int64 fortLevel + Int64 navalBaseLevel Int64 railroadLevel - + string regionId string continentId } diff --git a/docs/styleguide-cpp.md b/docs/styleguide-cpp.md index 69471f5..6440314 100644 --- a/docs/styleguide-cpp.md +++ b/docs/styleguide-cpp.md @@ -1,4 +1,4 @@ -# OpenVic2 C++ Style Guidelines +# OpenVic2 C++ Style Guidelines ## Table of Contents 1. [Why Style?](styleguide-cpp.md#1-why-style) @@ -169,7 +169,7 @@ Source code files should adhere to the following: longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight); - + //Incorrect callingAFunctionWithAVeryLongNameAndManyArguments(longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight); ``` @@ -255,7 +255,7 @@ Source code files should adhere to the following: - For constant values that are computable at compile-time, use `constexpr` instead of the `const` keyword ```c++ //Correct - constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; + constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; //Incorrect const size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; diff --git a/game/art/economy/goods/Aeroplanes.png.import b/game/art/economy/goods/Aeroplanes.png.import new file mode 100644 index 0000000..3d2451a --- /dev/null +++ b/game/art/economy/goods/Aeroplanes.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dv3expfaaeuln" +path="res://.godot/imported/Aeroplanes.png-f64f9804b1d78b1cd5836ee405e25434.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Aeroplanes.png" +dest_files=["res://.godot/imported/Aeroplanes.png-f64f9804b1d78b1cd5836ee405e25434.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Ammunition.png.import b/game/art/economy/goods/Ammunition.png.import new file mode 100644 index 0000000..18de665 --- /dev/null +++ b/game/art/economy/goods/Ammunition.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdntq1bof843k" +path="res://.godot/imported/Ammunition.png-2e4f424caeca5b92996fde71a1ab6ae6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Ammunition.png" +dest_files=["res://.godot/imported/Ammunition.png-2e4f424caeca5b92996fde71a1ab6ae6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Artillery.png.import b/game/art/economy/goods/Artillery.png.import new file mode 100644 index 0000000..d14e6d0 --- /dev/null +++ b/game/art/economy/goods/Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brr6ui0bfenjx" +path="res://.godot/imported/Artillery.png-e0bec54cd168f9abf3ab759e5d28a7d8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Artillery.png" +dest_files=["res://.godot/imported/Artillery.png-e0bec54cd168f9abf3ab759e5d28a7d8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Automobiles.png.import b/game/art/economy/goods/Automobiles.png.import new file mode 100644 index 0000000..4dbc7f3 --- /dev/null +++ b/game/art/economy/goods/Automobiles.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsbo2ysikx2pl" +path="res://.godot/imported/Automobiles.png-2a9cf7764eccefabb2bf9877b31b9df4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Automobiles.png" +dest_files=["res://.godot/imported/Automobiles.png-2a9cf7764eccefabb2bf9877b31b9df4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/CannedFood.png.import b/game/art/economy/goods/CannedFood.png.import new file mode 100644 index 0000000..4ef0744 --- /dev/null +++ b/game/art/economy/goods/CannedFood.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bohmpug1q1055" +path="res://.godot/imported/CannedFood.png-7e9c65b73180ffd48293ab7044e59b65.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/CannedFood.png" +dest_files=["res://.godot/imported/CannedFood.png-7e9c65b73180ffd48293ab7044e59b65.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Cattle.png.import b/game/art/economy/goods/Cattle.png.import new file mode 100644 index 0000000..203e9c9 --- /dev/null +++ b/game/art/economy/goods/Cattle.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qvjxhaoul0hd" +path="res://.godot/imported/Cattle.png-0ef679bb3a47dc39d334f87f1f7f33d0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Cattle.png" +dest_files=["res://.godot/imported/Cattle.png-0ef679bb3a47dc39d334f87f1f7f33d0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Cement.png.import b/game/art/economy/goods/Cement.png.import new file mode 100644 index 0000000..00dde5e --- /dev/null +++ b/game/art/economy/goods/Cement.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://u81g2lk4fdmw" +path="res://.godot/imported/Cement.png-7e727795f0350e73eddec47889a21c5e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Cement.png" +dest_files=["res://.godot/imported/Cement.png-7e727795f0350e73eddec47889a21c5e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/ClipperConvoys.png.import b/game/art/economy/goods/ClipperConvoys.png.import new file mode 100644 index 0000000..581ad9e --- /dev/null +++ b/game/art/economy/goods/ClipperConvoys.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dlvkgmqv1lvu3" +path="res://.godot/imported/ClipperConvoys.png-159028b2922e35ecf2dcbfccd801cf86.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/ClipperConvoys.png" +dest_files=["res://.godot/imported/ClipperConvoys.png-159028b2922e35ecf2dcbfccd801cf86.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Coal.png.import b/game/art/economy/goods/Coal.png.import new file mode 100644 index 0000000..13de37f --- /dev/null +++ b/game/art/economy/goods/Coal.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d05ib0dx1ybw3" +path="res://.godot/imported/Coal.png-4c471088e5b174c53d56febb417d0ea3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Coal.png" +dest_files=["res://.godot/imported/Coal.png-4c471088e5b174c53d56febb417d0ea3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Coffee.png.import b/game/art/economy/goods/Coffee.png.import new file mode 100644 index 0000000..0c32849 --- /dev/null +++ b/game/art/economy/goods/Coffee.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmb4lygh1p05u" +path="res://.godot/imported/Coffee.png-4e4c1279a8965c64feba98816229f183.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Coffee.png" +dest_files=["res://.godot/imported/Coffee.png-4e4c1279a8965c64feba98816229f183.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Cotton.png.import b/game/art/economy/goods/Cotton.png.import new file mode 100644 index 0000000..8d0b816 --- /dev/null +++ b/game/art/economy/goods/Cotton.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://beh58y5y1rulq" +path="res://.godot/imported/Cotton.png-e7a9a26df0e3cb09e7f774048297a99b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Cotton.png" +dest_files=["res://.godot/imported/Cotton.png-e7a9a26df0e3cb09e7f774048297a99b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Dye.png.import b/game/art/economy/goods/Dye.png.import new file mode 100644 index 0000000..5c74456 --- /dev/null +++ b/game/art/economy/goods/Dye.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6cj4nyn2ox0i" +path="res://.godot/imported/Dye.png-95addae97d31427aaf5a96fdc20b28b7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Dye.png" +dest_files=["res://.godot/imported/Dye.png-95addae97d31427aaf5a96fdc20b28b7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/ElectricGear.png.import b/game/art/economy/goods/ElectricGear.png.import new file mode 100644 index 0000000..a0bb59a --- /dev/null +++ b/game/art/economy/goods/ElectricGear.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fumygkymqhit" +path="res://.godot/imported/ElectricGear.png-8a9b67b515c96e0a0971c4c9eac2278d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/ElectricGear.png" +dest_files=["res://.godot/imported/ElectricGear.png-8a9b67b515c96e0a0971c4c9eac2278d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Explosives.png.import b/game/art/economy/goods/Explosives.png.import new file mode 100644 index 0000000..6edde00 --- /dev/null +++ b/game/art/economy/goods/Explosives.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c34svjqn86f3s" +path="res://.godot/imported/Explosives.png-d7cbb8033e9cf83a94115ff58e1cceec.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Explosives.png" +dest_files=["res://.godot/imported/Explosives.png-d7cbb8033e9cf83a94115ff58e1cceec.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Fabric.png.import b/game/art/economy/goods/Fabric.png.import new file mode 100644 index 0000000..557da36 --- /dev/null +++ b/game/art/economy/goods/Fabric.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgch0t83ofxt" +path="res://.godot/imported/Fabric.png-f640354692635eb1afd109feef624b45.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Fabric.png" +dest_files=["res://.godot/imported/Fabric.png-f640354692635eb1afd109feef624b45.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Fertilizer.png.import b/game/art/economy/goods/Fertilizer.png.import new file mode 100644 index 0000000..068e533 --- /dev/null +++ b/game/art/economy/goods/Fertilizer.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dy46mh5o0dyyf" +path="res://.godot/imported/Fertilizer.png-c2a9407f34cedd7f2bbd3614c6070ab8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Fertilizer.png" +dest_files=["res://.godot/imported/Fertilizer.png-c2a9407f34cedd7f2bbd3614c6070ab8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Fish.png.import b/game/art/economy/goods/Fish.png.import new file mode 100644 index 0000000..9cca12b --- /dev/null +++ b/game/art/economy/goods/Fish.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://u42bt5v5vx42" +path="res://.godot/imported/Fish.png-c8cef591ba5252382b7f603bee886146.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Fish.png" +dest_files=["res://.godot/imported/Fish.png-c8cef591ba5252382b7f603bee886146.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Fruit.png.import b/game/art/economy/goods/Fruit.png.import new file mode 100644 index 0000000..059b488 --- /dev/null +++ b/game/art/economy/goods/Fruit.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfr8rxa43dhfk" +path="res://.godot/imported/Fruit.png-6e3c553c5a8bd67d505ae0751d391712.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Fruit.png" +dest_files=["res://.godot/imported/Fruit.png-6e3c553c5a8bd67d505ae0751d391712.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Fuel.png.import b/game/art/economy/goods/Fuel.png.import new file mode 100644 index 0000000..9584b8d --- /dev/null +++ b/game/art/economy/goods/Fuel.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcmw4c8vcjt1w" +path="res://.godot/imported/Fuel.png-d4cce318e3b1cf2b2846d0bf589b2e56.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Fuel.png" +dest_files=["res://.godot/imported/Fuel.png-d4cce318e3b1cf2b2846d0bf589b2e56.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Furniture.png.import b/game/art/economy/goods/Furniture.png.import new file mode 100644 index 0000000..422ea21 --- /dev/null +++ b/game/art/economy/goods/Furniture.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccvpkwsm0gn0i" +path="res://.godot/imported/Furniture.png-116e7f7a3708afa2cee87e79151e10ef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Furniture.png" +dest_files=["res://.godot/imported/Furniture.png-116e7f7a3708afa2cee87e79151e10ef.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Glass.png.import b/game/art/economy/goods/Glass.png.import new file mode 100644 index 0000000..54383f6 --- /dev/null +++ b/game/art/economy/goods/Glass.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0qwt4tbqic4q" +path="res://.godot/imported/Glass.png-a801ee62345932edc9b2cf10740cc3fe.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Glass.png" +dest_files=["res://.godot/imported/Glass.png-a801ee62345932edc9b2cf10740cc3fe.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Grain.png.import b/game/art/economy/goods/Grain.png.import new file mode 100644 index 0000000..f1ca97a --- /dev/null +++ b/game/art/economy/goods/Grain.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cp45p4adg03ia" +path="res://.godot/imported/Grain.png-9ca7aa6f52786e3b8c0755fe3b032801.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Grain.png" +dest_files=["res://.godot/imported/Grain.png-9ca7aa6f52786e3b8c0755fe3b032801.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Iron.png.import b/game/art/economy/goods/Iron.png.import new file mode 100644 index 0000000..4e0c276 --- /dev/null +++ b/game/art/economy/goods/Iron.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://deubji56a8101" +path="res://.godot/imported/Iron.png-bc3abc240fd156b77f46e8b04178d267.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Iron.png" +dest_files=["res://.godot/imported/Iron.png-bc3abc240fd156b77f46e8b04178d267.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Liquor.png.import b/game/art/economy/goods/Liquor.png.import new file mode 100644 index 0000000..20d0eb2 --- /dev/null +++ b/game/art/economy/goods/Liquor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://f4kjlktvm2r2" +path="res://.godot/imported/Liquor.png-10c1257a0d7236955a0274bbd88341ba.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Liquor.png" +dest_files=["res://.godot/imported/Liquor.png-10c1257a0d7236955a0274bbd88341ba.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Lumber.png.import b/game/art/economy/goods/Lumber.png.import new file mode 100644 index 0000000..d93954a --- /dev/null +++ b/game/art/economy/goods/Lumber.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ba7mptrphkaqd" +path="res://.godot/imported/Lumber.png-85cdb47c3db3dee028b541aa407ce5bc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Lumber.png" +dest_files=["res://.godot/imported/Lumber.png-85cdb47c3db3dee028b541aa407ce5bc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/LuxuryClothes.png.import b/game/art/economy/goods/LuxuryClothes.png.import new file mode 100644 index 0000000..52b7adb --- /dev/null +++ b/game/art/economy/goods/LuxuryClothes.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ce3wvhvqcy1d2" +path="res://.godot/imported/LuxuryClothes.png-3d5d3b7653f1bcfe4c45e96265494a94.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/LuxuryClothes.png" +dest_files=["res://.godot/imported/LuxuryClothes.png-3d5d3b7653f1bcfe4c45e96265494a94.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/LuxuryFurniture.png.import b/game/art/economy/goods/LuxuryFurniture.png.import new file mode 100644 index 0000000..4b8a812 --- /dev/null +++ b/game/art/economy/goods/LuxuryFurniture.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckrs01pbwvk1j" +path="res://.godot/imported/LuxuryFurniture.png-8414a4d701c4ceb3bb78500f81eb9f1c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/LuxuryFurniture.png" +dest_files=["res://.godot/imported/LuxuryFurniture.png-8414a4d701c4ceb3bb78500f81eb9f1c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/MachineParts.png.import b/game/art/economy/goods/MachineParts.png.import new file mode 100644 index 0000000..2972256 --- /dev/null +++ b/game/art/economy/goods/MachineParts.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dyssc4fyvg0i0" +path="res://.godot/imported/MachineParts.png-31ee9b4bc155ba76c9068820493dc7c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/MachineParts.png" +dest_files=["res://.godot/imported/MachineParts.png-31ee9b4bc155ba76c9068820493dc7c5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Oil.png.import b/game/art/economy/goods/Oil.png.import new file mode 100644 index 0000000..464660a --- /dev/null +++ b/game/art/economy/goods/Oil.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c05in6w2pfu7a" +path="res://.godot/imported/Oil.png-822e9dd049ab1453614ebbfdd1b38454.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Oil.png" +dest_files=["res://.godot/imported/Oil.png-822e9dd049ab1453614ebbfdd1b38454.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Opium.png.import b/game/art/economy/goods/Opium.png.import new file mode 100644 index 0000000..d9bbe15 --- /dev/null +++ b/game/art/economy/goods/Opium.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dn1ex6s23wjvd" +path="res://.godot/imported/Opium.png-e336924c62c7eb8e056df2ecd312f451.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Opium.png" +dest_files=["res://.godot/imported/Opium.png-e336924c62c7eb8e056df2ecd312f451.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Paper.png.import b/game/art/economy/goods/Paper.png.import new file mode 100644 index 0000000..3cc304d --- /dev/null +++ b/game/art/economy/goods/Paper.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://evev4ofp0yv7" +path="res://.godot/imported/Paper.png-ec2a07dd74f449d1555735b89127e044.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Paper.png" +dest_files=["res://.godot/imported/Paper.png-ec2a07dd74f449d1555735b89127e044.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/PreciousMetal.png.import b/game/art/economy/goods/PreciousMetal.png.import new file mode 100644 index 0000000..726b023 --- /dev/null +++ b/game/art/economy/goods/PreciousMetal.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://copn3xhj12vwc" +path="res://.godot/imported/PreciousMetal.png-27348530d09ac15718b658314d037f79.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/PreciousMetal.png" +dest_files=["res://.godot/imported/PreciousMetal.png-27348530d09ac15718b658314d037f79.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Radios.png.import b/game/art/economy/goods/Radios.png.import new file mode 100644 index 0000000..bb91ffd --- /dev/null +++ b/game/art/economy/goods/Radios.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8e3casrgmmot" +path="res://.godot/imported/Radios.png-5025dbef9a0f9e4874cc904b557186c3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Radios.png" +dest_files=["res://.godot/imported/Radios.png-5025dbef9a0f9e4874cc904b557186c3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/RegularClothes.png.import b/game/art/economy/goods/RegularClothes.png.import new file mode 100644 index 0000000..4988d39 --- /dev/null +++ b/game/art/economy/goods/RegularClothes.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2rt64gc6vn8w" +path="res://.godot/imported/RegularClothes.png-bb54e5df7996148886ae0a19afbbcaaf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/RegularClothes.png" +dest_files=["res://.godot/imported/RegularClothes.png-bb54e5df7996148886ae0a19afbbcaaf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Rubber.png.import b/game/art/economy/goods/Rubber.png.import new file mode 100644 index 0000000..80fde27 --- /dev/null +++ b/game/art/economy/goods/Rubber.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgvppu138phcu" +path="res://.godot/imported/Rubber.png-fb0013e7ac71289b464202fbfe17a41c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Rubber.png" +dest_files=["res://.godot/imported/Rubber.png-fb0013e7ac71289b464202fbfe17a41c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Silk.png.import b/game/art/economy/goods/Silk.png.import new file mode 100644 index 0000000..adb2acc --- /dev/null +++ b/game/art/economy/goods/Silk.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbc1lb1aqxrok" +path="res://.godot/imported/Silk.png-013589539223b8fc4be0f091282266b0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Silk.png" +dest_files=["res://.godot/imported/Silk.png-013589539223b8fc4be0f091282266b0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/SmallArms.png.import b/game/art/economy/goods/SmallArms.png.import new file mode 100644 index 0000000..cd68f36 --- /dev/null +++ b/game/art/economy/goods/SmallArms.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://sxwrp1o87mad" +path="res://.godot/imported/SmallArms.png-f90e4e981a7cc5edb84c09bfd86d45f6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/SmallArms.png" +dest_files=["res://.godot/imported/SmallArms.png-f90e4e981a7cc5edb84c09bfd86d45f6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/SteamerConvoys.png.import b/game/art/economy/goods/SteamerConvoys.png.import new file mode 100644 index 0000000..2df38b7 --- /dev/null +++ b/game/art/economy/goods/SteamerConvoys.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ixlxhne7762f" +path="res://.godot/imported/SteamerConvoys.png-a0f19ac48200d954be7e73f961899ebc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/SteamerConvoys.png" +dest_files=["res://.godot/imported/SteamerConvoys.png-a0f19ac48200d954be7e73f961899ebc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Steel.png.import b/game/art/economy/goods/Steel.png.import new file mode 100644 index 0000000..3fbb5cc --- /dev/null +++ b/game/art/economy/goods/Steel.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://u72ecpwc4ued" +path="res://.godot/imported/Steel.png-8640de27c835c010f4ae43926b750ebb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Steel.png" +dest_files=["res://.godot/imported/Steel.png-8640de27c835c010f4ae43926b750ebb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Sulphur.png.import b/game/art/economy/goods/Sulphur.png.import new file mode 100644 index 0000000..2b7c7b0 --- /dev/null +++ b/game/art/economy/goods/Sulphur.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://di5qdxsgmmeso" +path="res://.godot/imported/Sulphur.png-51f6a765f564214878392306f69a5a1e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Sulphur.png" +dest_files=["res://.godot/imported/Sulphur.png-51f6a765f564214878392306f69a5a1e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Tanks.png.import b/game/art/economy/goods/Tanks.png.import new file mode 100644 index 0000000..cd8a225 --- /dev/null +++ b/game/art/economy/goods/Tanks.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dgdmiswjye8bc" +path="res://.godot/imported/Tanks.png-cff91aa93834fa6ee4ae3072bfe8ba65.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Tanks.png" +dest_files=["res://.godot/imported/Tanks.png-cff91aa93834fa6ee4ae3072bfe8ba65.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Tea.png.import b/game/art/economy/goods/Tea.png.import new file mode 100644 index 0000000..1a8ccbb --- /dev/null +++ b/game/art/economy/goods/Tea.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0jadcjnk8baj" +path="res://.godot/imported/Tea.png-ba317b3403a4b7c4cf85c588e48d7f37.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Tea.png" +dest_files=["res://.godot/imported/Tea.png-ba317b3403a4b7c4cf85c588e48d7f37.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Telephones.png.import b/game/art/economy/goods/Telephones.png.import new file mode 100644 index 0000000..f69e37b --- /dev/null +++ b/game/art/economy/goods/Telephones.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b2lefnj8r8csk" +path="res://.godot/imported/Telephones.png-96111950d02e51d0a7b4a3da0be5a8b7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Telephones.png" +dest_files=["res://.godot/imported/Telephones.png-96111950d02e51d0a7b4a3da0be5a8b7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Timber.png.import b/game/art/economy/goods/Timber.png.import new file mode 100644 index 0000000..ef2d1c4 --- /dev/null +++ b/game/art/economy/goods/Timber.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvmajoybi4mpx" +path="res://.godot/imported/Timber.png-6bbb5df327d5f86e822a9573fafe2559.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Timber.png" +dest_files=["res://.godot/imported/Timber.png-6bbb5df327d5f86e822a9573fafe2559.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Tobacco.png.import b/game/art/economy/goods/Tobacco.png.import new file mode 100644 index 0000000..2f3b067 --- /dev/null +++ b/game/art/economy/goods/Tobacco.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duywblje3mtuc" +path="res://.godot/imported/Tobacco.png-15d944a475ff2581c18e69ab81117162.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Tobacco.png" +dest_files=["res://.godot/imported/Tobacco.png-15d944a475ff2581c18e69ab81117162.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/TropicalWood.png.import b/game/art/economy/goods/TropicalWood.png.import new file mode 100644 index 0000000..e527cc3 --- /dev/null +++ b/game/art/economy/goods/TropicalWood.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bl4y0v6iqigsm" +path="res://.godot/imported/TropicalWood.png-b034631744d40b9c6708952b6226ae05.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/TropicalWood.png" +dest_files=["res://.godot/imported/TropicalWood.png-b034631744d40b9c6708952b6226ae05.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Wine.png.import b/game/art/economy/goods/Wine.png.import new file mode 100644 index 0000000..d639f2d --- /dev/null +++ b/game/art/economy/goods/Wine.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5b1mst7e148p" +path="res://.godot/imported/Wine.png-54a8f9decc5c6357daf1bff489288e2d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Wine.png" +dest_files=["res://.godot/imported/Wine.png-54a8f9decc5c6357daf1bff489288e2d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/economy/goods/Wool.png.import b/game/art/economy/goods/Wool.png.import new file mode 100644 index 0000000..a004986 --- /dev/null +++ b/game/art/economy/goods/Wool.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yfj36hk5ikvw" +path="res://.godot/imported/Wool.png-8d246d932f235d68b783ad3d290285cb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/economy/goods/Wool.png" +dest_files=["res://.godot/imported/Wool.png-8d246d932f235d68b783ad3d290285cb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Army Decision Making.png.import b/game/art/technology/army/Army Decision Making.png.import new file mode 100644 index 0000000..736bee3 --- /dev/null +++ b/game/art/technology/army/Army Decision Making.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dckthf8dux76m" +path="res://.godot/imported/Army Decision Making.png-de56087375aabbf13116266546faa432.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Army Decision Making.png" +dest_files=["res://.godot/imported/Army Decision Making.png-de56087375aabbf13116266546faa432.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Army NCO Training.png.import b/game/art/technology/army/Army NCO Training.png.import new file mode 100644 index 0000000..b12590b --- /dev/null +++ b/game/art/technology/army/Army NCO Training.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctfu58uqxj5pf" +path="res://.godot/imported/Army NCO Training.png-821f0f46c556e9cf3b61fa3790f53961.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Army NCO Training.png" +dest_files=["res://.godot/imported/Army NCO Training.png-821f0f46c556e9cf3b61fa3790f53961.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Army Professionalism.png.import b/game/art/technology/army/Army Professionalism.png.import new file mode 100644 index 0000000..5ca9b32 --- /dev/null +++ b/game/art/technology/army/Army Professionalism.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://43kk6efdupms" +path="res://.godot/imported/Army Professionalism.png-3303d162aeb25fa8cead9cd12a151bdf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Army Professionalism.png" +dest_files=["res://.godot/imported/Army Professionalism.png-3303d162aeb25fa8cead9cd12a151bdf.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Army Risk Management.png.import b/game/art/technology/army/Army Risk Management.png.import new file mode 100644 index 0000000..7e3af00 --- /dev/null +++ b/game/art/technology/army/Army Risk Management.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxjxl36ycaagx" +path="res://.godot/imported/Army Risk Management.png-d4c5a789328eafcefc15f4290af86b0d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Army Risk Management.png" +dest_files=["res://.godot/imported/Army Risk Management.png-d4c5a789328eafcefc15f4290af86b0d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Bolt-action Rifle.png.import b/game/art/technology/army/Bolt-action Rifle.png.import new file mode 100644 index 0000000..dd05df0 --- /dev/null +++ b/game/art/technology/army/Bolt-action Rifle.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dnbo2i4corwsf" +path="res://.godot/imported/Bolt-action Rifle.png-4952029366c5c5fa7365f610175bc54d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Bolt-action Rifle.png" +dest_files=["res://.godot/imported/Bolt-action Rifle.png-4952029366c5c5fa7365f610175bc54d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Breech-Loaded Rifles.png.import b/game/art/technology/army/Breech-Loaded Rifles.png.import new file mode 100644 index 0000000..15eb654 --- /dev/null +++ b/game/art/technology/army/Breech-Loaded Rifles.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dri3wrewyf13r" +path="res://.godot/imported/Breech-Loaded Rifles.png-0a1a7219ca3c5265d85a580eb205a6c1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Breech-Loaded Rifles.png" +dest_files=["res://.godot/imported/Breech-Loaded Rifles.png-0a1a7219ca3c5265d85a580eb205a6c1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Bronze Muzzle-loaded Artillery.png.import b/game/art/technology/army/Bronze Muzzle-loaded Artillery.png.import new file mode 100644 index 0000000..7baa8c4 --- /dev/null +++ b/game/art/technology/army/Bronze Muzzle-loaded Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bx2w63j11of83" +path="res://.godot/imported/Bronze Muzzle-loaded Artillery.png-a206f30df41008ce524d81461e3f725a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Bronze Muzzle-loaded Artillery.png" +dest_files=["res://.godot/imported/Bronze Muzzle-loaded Artillery.png-a206f30df41008ce524d81461e3f725a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Deep Defense System.png.import b/game/art/technology/army/Deep Defense System.png.import new file mode 100644 index 0000000..810c88b --- /dev/null +++ b/game/art/technology/army/Deep Defense System.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dihxim0oemat6" +path="res://.godot/imported/Deep Defense System.png-1ef6b4036bbfd0934f46f40fb02d30ac.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Deep Defense System.png" +dest_files=["res://.godot/imported/Deep Defense System.png-1ef6b4036bbfd0934f46f40fb02d30ac.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Flintlock Rifles.png.import b/game/art/technology/army/Flintlock Rifles.png.import new file mode 100644 index 0000000..65894cd --- /dev/null +++ b/game/art/technology/army/Flintlock Rifles.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://786ytfkafkyd" +path="res://.godot/imported/Flintlock Rifles.png-59fc48db6543edee17194c6fd6c10eef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Flintlock Rifles.png" +dest_files=["res://.godot/imported/Flintlock Rifles.png-59fc48db6543edee17194c6fd6c10eef.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Indirect Artillery Fire.png.import b/game/art/technology/army/Indirect Artillery Fire.png.import new file mode 100644 index 0000000..50931c0 --- /dev/null +++ b/game/art/technology/army/Indirect Artillery Fire.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8xmx42ik0nhs" +path="res://.godot/imported/Indirect Artillery Fire.png-8d6eaed9cd7edcdbef53d4d1251ed9f7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Indirect Artillery Fire.png" +dest_files=["res://.godot/imported/Indirect Artillery Fire.png-8d6eaed9cd7edcdbef53d4d1251ed9f7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Infiltration.png.import b/game/art/technology/army/Infiltration.png.import new file mode 100644 index 0000000..a6697b3 --- /dev/null +++ b/game/art/technology/army/Infiltration.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bsfdmmu60tc3n" +path="res://.godot/imported/Infiltration.png-57a5e43cb820964cecd846278423621f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Infiltration.png" +dest_files=["res://.godot/imported/Infiltration.png-57a5e43cb820964cecd846278423621f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Iron Breech-Loaded Artillery.png.import b/game/art/technology/army/Iron Breech-Loaded Artillery.png.import new file mode 100644 index 0000000..993627c --- /dev/null +++ b/game/art/technology/army/Iron Breech-Loaded Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbsx7rfndoftn" +path="res://.godot/imported/Iron Breech-Loaded Artillery.png-4bac252ba7934897b162ed696b4b7509.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Iron Breech-Loaded Artillery.png" +dest_files=["res://.godot/imported/Iron Breech-Loaded Artillery.png-4bac252ba7934897b162ed696b4b7509.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Iron Muzzle-Loaded Artillery.png.import b/game/art/technology/army/Iron Muzzle-Loaded Artillery.png.import new file mode 100644 index 0000000..efa4e51 --- /dev/null +++ b/game/art/technology/army/Iron Muzzle-Loaded Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cq4kommomraba" +path="res://.godot/imported/Iron Muzzle-Loaded Artillery.png-5777c093343e4ec0cb88b085c086a1f7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Iron Muzzle-Loaded Artillery.png" +dest_files=["res://.godot/imported/Iron Muzzle-Loaded Artillery.png-5777c093343e4ec0cb88b085c086a1f7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Machine Gun.png.import b/game/art/technology/army/Machine Gun.png.import new file mode 100644 index 0000000..f6f3775 --- /dev/null +++ b/game/art/technology/army/Machine Gun.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgnd44ys1m4cf" +path="res://.godot/imported/Machine Gun.png-e853bb6291451d02084e1823c7a0d98f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Machine Gun.png" +dest_files=["res://.godot/imported/Machine Gun.png-e853bb6291451d02084e1823c7a0d98f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Military Directionism.png.import b/game/art/technology/army/Military Directionism.png.import new file mode 100644 index 0000000..17376e1 --- /dev/null +++ b/game/art/technology/army/Military Directionism.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dgx61xfpng6ka" +path="res://.godot/imported/Military Directionism.png-565e1e6381fc0f0d7fcb9195f249ca1a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Military Directionism.png" +dest_files=["res://.godot/imported/Military Directionism.png-565e1e6381fc0f0d7fcb9195f249ca1a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Military Logistics.png.import b/game/art/technology/army/Military Logistics.png.import new file mode 100644 index 0000000..0326305 --- /dev/null +++ b/game/art/technology/army/Military Logistics.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctoh8oq6afuki" +path="res://.godot/imported/Military Logistics.png-5748d86c74b85e45d6ee2d2f8d81f95a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Military Logistics.png" +dest_files=["res://.godot/imported/Military Logistics.png-5748d86c74b85e45d6ee2d2f8d81f95a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Military Plans.png.import b/game/art/technology/army/Military Plans.png.import new file mode 100644 index 0000000..d8e8b0a --- /dev/null +++ b/game/art/technology/army/Military Plans.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bslr0m3ca74y6" +path="res://.godot/imported/Military Plans.png-1a32d460e676e358dde057d988d707ac.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Military Plans.png" +dest_files=["res://.godot/imported/Military Plans.png-1a32d460e676e358dde057d988d707ac.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Military Staff System.png.import b/game/art/technology/army/Military Staff System.png.import new file mode 100644 index 0000000..844df8f --- /dev/null +++ b/game/art/technology/army/Military Staff System.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj6kw2ou4aoop" +path="res://.godot/imported/Military Staff System.png-094a056d8c546ed0da41d1f1dbcdb2a1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Military Staff System.png" +dest_files=["res://.godot/imported/Military Staff System.png-094a056d8c546ed0da41d1f1dbcdb2a1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Military Statistics.png.import b/game/art/technology/army/Military Statistics.png.import new file mode 100644 index 0000000..e495bd9 --- /dev/null +++ b/game/art/technology/army/Military Statistics.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8oww2lsc5sfe" +path="res://.godot/imported/Military Statistics.png-4941c660e22242166acf00038144df37.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Military Statistics.png" +dest_files=["res://.godot/imported/Military Statistics.png-4941c660e22242166acf00038144df37.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Muzzle-loaded Rifles.png.import b/game/art/technology/army/Muzzle-loaded Rifles.png.import new file mode 100644 index 0000000..5c79afd --- /dev/null +++ b/game/art/technology/army/Muzzle-loaded Rifles.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c1n4hwwt4jwv0" +path="res://.godot/imported/Muzzle-loaded Rifles.png-37ff916f6889925dc68e88b1251f14d7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Muzzle-loaded Rifles.png" +dest_files=["res://.godot/imported/Muzzle-loaded Rifles.png-37ff916f6889925dc68e88b1251f14d7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Point Defense System.png.import b/game/art/technology/army/Point Defense System.png.import new file mode 100644 index 0000000..b5b5b1c --- /dev/null +++ b/game/art/technology/army/Point Defense System.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckfv5gbcfij5m" +path="res://.godot/imported/Point Defense System.png-cdd4b2bbbf74fe5b0ebe7d2306d9d468.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Point Defense System.png" +dest_files=["res://.godot/imported/Point Defense System.png-cdd4b2bbbf74fe5b0ebe7d2306d9d468.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Post-Napoleonic Thought.png.import b/game/art/technology/army/Post-Napoleonic Thought.png.import new file mode 100644 index 0000000..2e963fc --- /dev/null +++ b/game/art/technology/army/Post-Napoleonic Thought.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bw2bidtorexob" +path="res://.godot/imported/Post-Napoleonic Thought.png-0c345d9286a8a1fd4b7bcbae60ec0250.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Post-Napoleonic Thought.png" +dest_files=["res://.godot/imported/Post-Napoleonic Thought.png-0c345d9286a8a1fd4b7bcbae60ec0250.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Steel Breech-Loaded Artillery.png.import b/game/art/technology/army/Steel Breech-Loaded Artillery.png.import new file mode 100644 index 0000000..92e374e --- /dev/null +++ b/game/art/technology/army/Steel Breech-Loaded Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cx15ctmi52kv1" +path="res://.godot/imported/Steel Breech-Loaded Artillery.png-2fdc9e71a5204d6d657b8ca9b4cfb3a0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Steel Breech-Loaded Artillery.png" +dest_files=["res://.godot/imported/Steel Breech-Loaded Artillery.png-2fdc9e71a5204d6d657b8ca9b4cfb3a0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/Strategic Mobility.png.import b/game/art/technology/army/Strategic Mobility.png.import new file mode 100644 index 0000000..890b896 --- /dev/null +++ b/game/art/technology/army/Strategic Mobility.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cac2g1uui35d5" +path="res://.godot/imported/Strategic Mobility.png-ceaba1342f52e5251521c79dcbf79951.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/Strategic Mobility.png" +dest_files=["res://.godot/imported/Strategic Mobility.png-ceaba1342f52e5251521c79dcbf79951.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/technology/army/The Command Principle.png.import b/game/art/technology/army/The Command Principle.png.import new file mode 100644 index 0000000..94c991f --- /dev/null +++ b/game/art/technology/army/The Command Principle.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://r3vxso20jcuf" +path="res://.godot/imported/The Command Principle.png-def1e8cd5ae5294984c171ffa624d74d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/technology/army/The Command Principle.png" +dest_files=["res://.godot/imported/The Command Principle.png-def1e8cd5ae5294984c171ffa624d74d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Airplane.png.import b/game/art/units/Airplane.png.import new file mode 100644 index 0000000..830c140 --- /dev/null +++ b/game/art/units/Airplane.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b05nq06fahtxi" +path="res://.godot/imported/Airplane.png-41f37b8f11a65e540eed98b24a297027.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Airplane.png" +dest_files=["res://.godot/imported/Airplane.png-41f37b8f11a65e540eed98b24a297027.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Armor.png.import b/game/art/units/Armor.png.import new file mode 100644 index 0000000..42c807b --- /dev/null +++ b/game/art/units/Armor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cr6bw4jwrydpm" +path="res://.godot/imported/Armor.png-748c76c2a00bae3705715d74bcf34c0b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Armor.png" +dest_files=["res://.godot/imported/Armor.png-748c76c2a00bae3705715d74bcf34c0b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Artillery.png.import b/game/art/units/Artillery.png.import new file mode 100644 index 0000000..5775e85 --- /dev/null +++ b/game/art/units/Artillery.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6q1scxdbxppv" +path="res://.godot/imported/Artillery.png-a510c953fca66ca6ad75d3de82213d2d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Artillery.png" +dest_files=["res://.godot/imported/Artillery.png-a510c953fca66ca6ad75d3de82213d2d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Battleship.png.import b/game/art/units/Battleship.png.import new file mode 100644 index 0000000..aa56ee7 --- /dev/null +++ b/game/art/units/Battleship.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://j16k5y0gnkqy" +path="res://.godot/imported/Battleship.png-ea7ecf7a355e55b030c9c7a6b1765d4e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Battleship.png" +dest_files=["res://.godot/imported/Battleship.png-ea7ecf7a355e55b030c9c7a6b1765d4e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Cavalry.png.import b/game/art/units/Cavalry.png.import new file mode 100644 index 0000000..7cc22ed --- /dev/null +++ b/game/art/units/Cavalry.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bmv2431sb27kw" +path="res://.godot/imported/Cavalry.png-e9b856b6c9804e5a46f98e084fb8322d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Cavalry.png" +dest_files=["res://.godot/imported/Cavalry.png-e9b856b6c9804e5a46f98e084fb8322d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/ClipperTransport.png.import b/game/art/units/ClipperTransport.png.import new file mode 100644 index 0000000..aa42ffd --- /dev/null +++ b/game/art/units/ClipperTransport.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bac3o2bng7o3y" +path="res://.godot/imported/ClipperTransport.png-9e61055011e1905d88dbc935d3804c84.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/ClipperTransport.png" +dest_files=["res://.godot/imported/ClipperTransport.png-9e61055011e1905d88dbc935d3804c84.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/CommerceRaider.png.import b/game/art/units/CommerceRaider.png.import new file mode 100644 index 0000000..9659365 --- /dev/null +++ b/game/art/units/CommerceRaider.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://df6xi485nd40t" +path="res://.godot/imported/CommerceRaider.png-bf8b21fe06d47d08c44cca1f8235510c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/CommerceRaider.png" +dest_files=["res://.godot/imported/CommerceRaider.png-bf8b21fe06d47d08c44cca1f8235510c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Cruiser.png.import b/game/art/units/Cruiser.png.import new file mode 100644 index 0000000..f66a5ef --- /dev/null +++ b/game/art/units/Cruiser.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ux2c2o7mdw62" +path="res://.godot/imported/Cruiser.png-1e3544dd1a241ffcae8270610e5bfe3d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Cruiser.png" +dest_files=["res://.godot/imported/Cruiser.png-1e3544dd1a241ffcae8270610e5bfe3d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Cuirassier.png.import b/game/art/units/Cuirassier.png.import new file mode 100644 index 0000000..aa7a083 --- /dev/null +++ b/game/art/units/Cuirassier.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b1osxxowutu4m" +path="res://.godot/imported/Cuirassier.png-81579aef297026e6ff19205d26583582.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Cuirassier.png" +dest_files=["res://.godot/imported/Cuirassier.png-81579aef297026e6ff19205d26583582.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Dragoon.png.import b/game/art/units/Dragoon.png.import new file mode 100644 index 0000000..9d2cd04 --- /dev/null +++ b/game/art/units/Dragoon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cibsp68s8qaiu" +path="res://.godot/imported/Dragoon.png-54b62cf8d20f1dfb39bb19d654a4dc80.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Dragoon.png" +dest_files=["res://.godot/imported/Dragoon.png-54b62cf8d20f1dfb39bb19d654a4dc80.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Dreadnought.png.import b/game/art/units/Dreadnought.png.import new file mode 100644 index 0000000..3753e7b --- /dev/null +++ b/game/art/units/Dreadnought.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://380ikkcmhbtq" +path="res://.godot/imported/Dreadnought.png-aa8d52ce02a2bb43d1f13134ff4a3806.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Dreadnought.png" +dest_files=["res://.godot/imported/Dreadnought.png-aa8d52ce02a2bb43d1f13134ff4a3806.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Engineer.png.import b/game/art/units/Engineer.png.import new file mode 100644 index 0000000..9cf2a5c --- /dev/null +++ b/game/art/units/Engineer.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctaadlfgu8gsi" +path="res://.godot/imported/Engineer.png-f54fdaee08f72f0db7cae32666203020.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Engineer.png" +dest_files=["res://.godot/imported/Engineer.png-f54fdaee08f72f0db7cae32666203020.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Frigate.png.import b/game/art/units/Frigate.png.import new file mode 100644 index 0000000..58cbad4 --- /dev/null +++ b/game/art/units/Frigate.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cayh7gvg3rt2o" +path="res://.godot/imported/Frigate.png-22a37dd538d573dff9d19359d304af1a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Frigate.png" +dest_files=["res://.godot/imported/Frigate.png-22a37dd538d573dff9d19359d304af1a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Guard.png.import b/game/art/units/Guard.png.import new file mode 100644 index 0000000..859533b --- /dev/null +++ b/game/art/units/Guard.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcwqdjag2ebjl" +path="res://.godot/imported/Guard.png-e33328551a8b0c631b2c45a2eacf7946.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Guard.png" +dest_files=["res://.godot/imported/Guard.png-e33328551a8b0c631b2c45a2eacf7946.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Hussar.png.import b/game/art/units/Hussar.png.import new file mode 100644 index 0000000..b9ee901 --- /dev/null +++ b/game/art/units/Hussar.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1k07hjkw32yw" +path="res://.godot/imported/Hussar.png-f1c1708f6e6fc49464755bd5990c1772.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Hussar.png" +dest_files=["res://.godot/imported/Hussar.png-f1c1708f6e6fc49464755bd5990c1772.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Infantry.png.import b/game/art/units/Infantry.png.import new file mode 100644 index 0000000..e971024 --- /dev/null +++ b/game/art/units/Infantry.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djapkkohviqg8" +path="res://.godot/imported/Infantry.png-2f36f0119ae261a77a92edb77e583aa5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Infantry.png" +dest_files=["res://.godot/imported/Infantry.png-2f36f0119ae261a77a92edb77e583aa5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Ironclad.png.import b/game/art/units/Ironclad.png.import new file mode 100644 index 0000000..c21f9b5 --- /dev/null +++ b/game/art/units/Ironclad.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d2xvrhdb8ddbj" +path="res://.godot/imported/Ironclad.png-6ff432ba040c970e7cf5a34fa1691703.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Ironclad.png" +dest_files=["res://.godot/imported/Ironclad.png-6ff432ba040c970e7cf5a34fa1691703.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Irregular.png.import b/game/art/units/Irregular.png.import new file mode 100644 index 0000000..c5afc1f --- /dev/null +++ b/game/art/units/Irregular.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://k85dqi6f5h5b" +path="res://.godot/imported/Irregular.png-3def289eafc49bf0792a13dcfc57644e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Irregular.png" +dest_files=["res://.godot/imported/Irregular.png-3def289eafc49bf0792a13dcfc57644e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/ManOWar.png.import b/game/art/units/ManOWar.png.import new file mode 100644 index 0000000..95e8aae --- /dev/null +++ b/game/art/units/ManOWar.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhs14st1sfxyk" +path="res://.godot/imported/ManOWar.png-1d0aeaf29ddb7549ac6e1fe02bb71087.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/ManOWar.png" +dest_files=["res://.godot/imported/ManOWar.png-1d0aeaf29ddb7549ac6e1fe02bb71087.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/Monitor.png.import b/game/art/units/Monitor.png.import new file mode 100644 index 0000000..abce7fd --- /dev/null +++ b/game/art/units/Monitor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbr4cvn768avu" +path="res://.godot/imported/Monitor.png-67ac2d89ae01044a05ecd8ac7a4404e5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/Monitor.png" +dest_files=["res://.godot/imported/Monitor.png-67ac2d89ae01044a05ecd8ac7a4404e5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/art/units/SteamerTransport.png.import b/game/art/units/SteamerTransport.png.import new file mode 100644 index 0000000..4eece41 --- /dev/null +++ b/game/art/units/SteamerTransport.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csusa1o3uhn3b" +path="res://.godot/imported/SteamerTransport.png-a0d47379c05f4b7a05fb7e1f159d0614.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/units/SteamerTransport.png" +dest_files=["res://.godot/imported/SteamerTransport.png-a0d47379c05f4b7a05fb7e1f159d0614.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/src/MainMenu/MainMenu.tscn b/game/src/MainMenu/MainMenu.tscn index 5fb6ca9..a10fa27 100644 --- a/game/src/MainMenu/MainMenu.tscn +++ b/game/src/MainMenu/MainMenu.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=5 format=3 uid="uid://bp5n3mlu45ygw"] +[gd_scene load_steps=6 format=3 uid="uid://bp5n3mlu45ygw"] [ext_resource type="Theme" uid="uid://qoi3oec48jp0" path="res://theme/main_menu.tres" id="1_1yri4"] [ext_resource type="Script" path="res://src/MainMenu/MainMenu.gd" id="2_nm1fq"] +[ext_resource type="Texture2D" uid="uid://dxys0wg0f0ic5" path="res://theme/assets/OpenVicFINALREALTRANS.png" id="3_58ess"] [ext_resource type="PackedScene" uid="uid://b7oncobnacxmt" path="res://src/LocaleButton.tscn" id="3_amonp"] [ext_resource type="PackedScene" uid="uid://cen7wkmn6og66" path="res://src/MainMenu/ReleaseInfoBox.tscn" id="3_km0er"] @@ -29,14 +30,13 @@ theme_type_variation = &"BackgroundPanel" [node name="VBox" type="VBoxContainer" parent="Panel"] layout_mode = 2 -[node name="TitleLabel" type="Label" parent="Panel/VBox"] +[node name="TextureRect" type="TextureRect" parent="Panel/VBox"] layout_mode = 2 -size_flags_vertical = 6 -size_flags_stretch_ratio = 1.5 -theme_type_variation = &"TitleLabel" -text = "MAINMENU_TITLE" -horizontal_alignment = 1 -vertical_alignment = 1 +size_flags_vertical = 3 +size_flags_stretch_ratio = 1.75 +texture = ExtResource("3_58ess") +expand_mode = 1 +stretch_mode = 5 [node name="Margin" type="MarginContainer" parent="Panel/VBox"] layout_mode = 2 diff --git a/game/src/MusicConductor/MusicConductor.gd b/game/src/MusicConductor/MusicConductor.gd index c0cfc46..08fa86a 100644 --- a/game/src/MusicConductor/MusicConductor.gd +++ b/game/src/MusicConductor/MusicConductor.gd @@ -36,7 +36,7 @@ func is_paused() -> bool: func toggle_play_pause() -> void: $AudioStreamPlayer.stream_paused = !$AudioStreamPlayer.stream_paused - + func start_current_song() -> void: $AudioStreamPlayer.stream = _available_songs[_selected_track].song_stream $AudioStreamPlayer.play() diff --git a/game/theme/assets/OpenVicFINALREALTRANS.png b/game/theme/assets/OpenVicFINALREALTRANS.png new file mode 100644 index 0000000..446814f Binary files /dev/null and b/game/theme/assets/OpenVicFINALREALTRANS.png differ diff --git a/game/theme/assets/OpenVicFINALREALTRANS.png.import b/game/theme/assets/OpenVicFINALREALTRANS.png.import new file mode 100644 index 0000000..6963753 --- /dev/null +++ b/game/theme/assets/OpenVicFINALREALTRANS.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxys0wg0f0ic5" +path="res://.godot/imported/OpenVicFINALREALTRANS.png-be4facd2c0164660117ada12fd221f10.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://theme/assets/OpenVicFINALREALTRANS.png" +dest_files=["res://.godot/imported/OpenVicFINALREALTRANS.png-be4facd2c0164660117ada12fd221f10.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/theme/main_menu.tres b/game/theme/main_menu.tres index 24c5552..6a3f73d 100644 --- a/game/theme/main_menu.tres +++ b/game/theme/main_menu.tres @@ -189,8 +189,6 @@ TitleButton/styles/focus = SubResource("StyleBoxFlat_2txce") TitleButton/styles/hover = SubResource("StyleBoxTexture_3efxh") TitleButton/styles/normal = ExtResource("6_dx0aj") TitleButton/styles/pressed = SubResource("StyleBox_uuspe") -TitleLabel/base_type = &"Label" -TitleLabel/font_sizes/font_size = 90 VersionLabel/base_type = &"Button" VersionLabel/colors/font_hover_color = Color(0.360784, 0.360784, 0.360784, 1) VersionLabel/colors/font_hover_pressed_color = Color(0.215686, 0.215686, 0.215686, 1) -- cgit v1.2.3-56-ga3b1 From b01832e939b639c25ee4d60438517768b1d2173d Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Tue, 11 Apr 2023 10:59:40 -0400 Subject: Update to Godot 4.0.2 Stable Release Remove specific Godot version references for non-links in README.md --- .github/workflows/builds.yml | 8 ++++---- README.md | 8 ++++---- godot-cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 88d5200..772b16c 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -143,8 +143,8 @@ jobs: id: export_game uses: Spartan322/godot-export@master with: - godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0.1/Godot_v4.0.1-stable_linux.x86_64.zip - godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0.1/Godot_v4.0.1-stable_export_templates.tpz + godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0.2/Godot_v4.0.2-stable_linux.x86_64.zip + godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0.2/Godot_v4.0.2-stable_export_templates.tpz relative_project_path: ./game export_as_pack: true export_debug: true @@ -191,8 +191,8 @@ jobs: id: export_game uses: Spartan322/godot-export@master with: - godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0.1/Godot_v4.0.1-stable_linux.x86_64.zip - godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0.1/Godot_v4.0.1-stable_export_templates.tpz + godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0.2/Godot_v4.0.2-stable_linux.x86_64.zip + godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0.2/Godot_v4.0.2-stable_export_templates.tpz relative_project_path: ./game archive_output: true wine_path: ${{ steps.wine_install.outputs.WINE_PATH }} diff --git a/README.md b/README.md index 7f8a1d8..fed2e32 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,22 @@ Main Repo for the OpenVic2 Project For detailed instructions, view the Contributor Quickstart Guide [here](docs/contribution-quickstart-guide.md) ## Required -* [Godot 4.0.1](https://github.com/godotengine/godot/releases/tag/4.0.1-stable) +* [Godot 4.0.2](https://github.com/godotengine/godot/releases/tag/4.0.2-stable) * [scons](https://scons.org/) ## [Godot Documentation](https://docs.godotengine.org/en/latest/) ## Build/Run Instructions -1. Install [Godot 4.0.1](https://github.com/godotengine/godot/releases/tag/4.0.1-stable) and [scons](https://scons.org/) for your system. +1. Install [Godot 4.0.2](https://github.com/godotengine/godot/releases/tag/4.0.2-stable) and [scons](https://scons.org/) for your system. 2. Run the command `git submodule update --init --recursive` to retrieve all related submodules. 3. Run `scons` in the project root, you should see a libopenvic2 file in `game/bin/openvic2`. -4. Open with Godot 4.0.1, click import and navigate to the `game` directory. +4. Open with Godot 4, click import and navigate to the `game` directory. 5. Import and edit. 6. Once loaded, click the play button at the top right, if you see `Hello GDExtension Singleton!` in the output at the bottom then it is working. ## 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.0.1. +2. Open `game/project.godot` with Godot 4. 3. Click `Project` at the top left, click `Export`. 4. If you do not have the templates, you must download the templates, there is highlighted white text at the bottom of the Export subwindow that opens up the template manager for you to download. 5. Click `Export All`: diff --git a/godot-cpp b/godot-cpp index 4d3afc0..7fb46e9 160000 --- a/godot-cpp +++ b/godot-cpp @@ -1 +1 @@ -Subproject commit 4d3afc0ad0c5445831418830a33c6adb3e0a9aa8 +Subproject commit 7fb46e9ea1571b1364ab049b2088e9b302ff7985 -- cgit v1.2.3-56-ga3b1 From c0d76b78d3762e6eec3ed1c62618be84c5b7559b Mon Sep 17 00:00:00 2001 From: Hop311 Date: Thu, 30 Mar 2023 22:50:50 +0100 Subject: Add terrain map With Directional movement using WASD With Directional movement using arrow keys With Click-Drag movement using middle mouse button With Province identifiers With Province shape loading With Province rendering With Province selection With Province overview panel With Color lookup texture --- .gitignore | 1 + extension/src/LoadLocalisation.cpp | 8 +- extension/src/LoadLocalisation.hpp | 8 +- extension/src/MapMesh.cpp | 151 ++++++++++++++ extension/src/MapMesh.hpp | 34 ++++ extension/src/MapSingleton.cpp | 256 ++++++++++++++++++++++++ extension/src/MapSingleton.hpp | 34 ++++ extension/src/TestSingleton.cpp | 4 +- extension/src/TestSingleton.hpp | 4 +- extension/src/openvic2/Map.cpp | 89 ++++++++ extension/src/openvic2/Map.hpp | 45 +++++ extension/src/register_types.cpp | 20 +- game/common/map/provinces.json | 9 + game/common/map/provinces.png | Bin 0 -> 9464 bytes game/common/map/provinces.png.import | 3 + game/common/map/terrain/terrain.png | Bin 0 -> 27542091 bytes game/common/map/terrain/terrain.png.import | 34 ++++ game/localisation/en_GB/menus.csv | 1 + game/localisation/en_GB/provinces.csv | 9 + game/localisation/en_GB/provinces.csv.import | 3 + game/project.godot | 49 +++++ game/src/Autoload/Events.gd | 9 + game/src/GameSession/GameSession.gd | 2 +- game/src/GameSession/GameSession.tscn | 24 ++- game/src/GameSession/MapControlPanel.tscn | 9 +- game/src/GameSession/MapView.gd | 185 +++++++++++++++++ game/src/GameSession/MapView.tscn | 27 +++ game/src/GameSession/ProvinceOverviewPanel.gd | 22 ++ game/src/GameSession/ProvinceOverviewPanel.tscn | 40 ++++ game/src/GameSession/TerrainMap.gdshader | 48 +++++ 30 files changed, 1098 insertions(+), 30 deletions(-) create mode 100644 extension/src/MapMesh.cpp create mode 100644 extension/src/MapMesh.hpp create mode 100644 extension/src/MapSingleton.cpp create mode 100644 extension/src/MapSingleton.hpp create mode 100644 extension/src/openvic2/Map.cpp create mode 100644 extension/src/openvic2/Map.hpp create mode 100644 game/common/map/provinces.json create mode 100644 game/common/map/provinces.png create mode 100644 game/common/map/provinces.png.import create mode 100644 game/common/map/terrain/terrain.png create mode 100644 game/common/map/terrain/terrain.png.import create mode 100644 game/localisation/en_GB/provinces.csv create mode 100644 game/localisation/en_GB/provinces.csv.import create mode 100644 game/src/GameSession/MapView.gd create mode 100644 game/src/GameSession/MapView.tscn create mode 100644 game/src/GameSession/ProvinceOverviewPanel.gd create mode 100644 game/src/GameSession/ProvinceOverviewPanel.tscn create mode 100644 game/src/GameSession/TerrainMap.gdshader diff --git a/.gitignore b/.gitignore index 92118b7..125f143 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,4 @@ bin/* .DS_Store *.translation +!game/common/map/*.obj \ No newline at end of file diff --git a/extension/src/LoadLocalisation.cpp b/extension/src/LoadLocalisation.cpp index c95c08b..8698bb2 100644 --- a/extension/src/LoadLocalisation.cpp +++ b/extension/src/LoadLocalisation.cpp @@ -8,7 +8,7 @@ using namespace godot; using namespace OpenVic2; -LoadLocalisation *LoadLocalisation::singleton = nullptr; +LoadLocalisation* LoadLocalisation::singleton = nullptr; void LoadLocalisation::_bind_methods() { ClassDB::bind_method(D_METHOD("load_file", "file_path", "locale"), &LoadLocalisation::load_file); @@ -16,7 +16,7 @@ void LoadLocalisation::_bind_methods() { ClassDB::bind_method(D_METHOD("load_localisation_dir", "dir_path"), &LoadLocalisation::load_localisation_dir); } -LoadLocalisation *LoadLocalisation::get_singleton() { +LoadLocalisation* LoadLocalisation::get_singleton() { return singleton; } @@ -54,7 +54,7 @@ Error LoadLocalisation::_load_file_into_translation(String const& file_path, Ref } Ref LoadLocalisation::_get_translation(String const& locale) { - TranslationServer *server = TranslationServer::get_singleton(); + TranslationServer* server = TranslationServer::get_singleton(); Ref translation = server->get_translation_object(locale); if (translation.is_null() || translation->get_locale() != locale) { translation.instantiate(); @@ -93,7 +93,7 @@ Error LoadLocalisation::load_locale_dir(String const& dir_path, String const& lo */ Error LoadLocalisation::load_localisation_dir(String const& dir_path) { if (DirAccess::dir_exists_absolute(dir_path)) { - TranslationServer *server = TranslationServer::get_singleton(); + TranslationServer* server = TranslationServer::get_singleton(); Error err = OK; for (String const& locale_name : DirAccess::get_directories_at(dir_path)) { if (locale_name == server->standardize_locale(locale_name)) { diff --git a/extension/src/LoadLocalisation.hpp b/extension/src/LoadLocalisation.hpp index 90f3158..f54a025 100644 --- a/extension/src/LoadLocalisation.hpp +++ b/extension/src/LoadLocalisation.hpp @@ -4,11 +4,11 @@ #include namespace OpenVic2 { - class LoadLocalisation : public godot::Object - { + class LoadLocalisation : public godot::Object { + GDCLASS(LoadLocalisation, godot::Object) - static LoadLocalisation *singleton; + static LoadLocalisation* singleton; godot::Error _load_file_into_translation(godot::String const& file_path, godot::Ref translation); godot::Ref _get_translation(godot::String const& locale); @@ -17,7 +17,7 @@ namespace OpenVic2 { static void _bind_methods(); public: - static LoadLocalisation *get_singleton(); + static LoadLocalisation* get_singleton(); LoadLocalisation(); ~LoadLocalisation(); diff --git a/extension/src/MapMesh.cpp b/extension/src/MapMesh.cpp new file mode 100644 index 0000000..f0fc819 --- /dev/null +++ b/extension/src/MapMesh.cpp @@ -0,0 +1,151 @@ +#include "MapMesh.hpp" + +#include + +using namespace godot; +using namespace OpenVic2; + +void MapMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_aspect_ratio", "ratio"), &MapMesh::set_aspect_ratio); + ClassDB::bind_method(D_METHOD("get_aspect_ratio"), &MapMesh::get_aspect_ratio); + + ClassDB::bind_method(D_METHOD("set_repeat_proportion", "proportion"), &MapMesh::set_repeat_proportion); + ClassDB::bind_method(D_METHOD("get_repeat_proportion"), &MapMesh::get_repeat_proportion); + + ClassDB::bind_method(D_METHOD("set_subdivide_width", "divisions"), &MapMesh::set_subdivide_width); + ClassDB::bind_method(D_METHOD("get_subdivide_width"), &MapMesh::get_subdivide_width); + + ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &MapMesh::set_subdivide_depth); + ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &MapMesh::get_subdivide_depth); + + ClassDB::bind_method(D_METHOD("get_core_aabb"), &MapMesh::get_core_aabb); + ClassDB::bind_method(D_METHOD("is_valid_uv_coord"), &MapMesh::is_valid_uv_coord); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "aspect_ratio", PROPERTY_HINT_NONE, "suffix:m"), "set_aspect_ratio", "get_aspect_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "repeat_proportion", PROPERTY_HINT_NONE, "suffix:m"), "set_repeat_proportion", "get_repeat_proportion"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); +} + +void MapMesh::_request_update() { + // Hack to trigger _update_lightmap_size and _request_update in PrimitiveMesh + set_add_uv2(get_add_uv2()); +} + +void MapMesh::set_aspect_ratio(const float ratio) { + aspect_ratio = ratio; + _request_update(); +} + +float MapMesh::get_aspect_ratio() const { + return aspect_ratio; +} + +void MapMesh::set_repeat_proportion(const float proportion) { + repeat_proportion = proportion; + _request_update(); +} + +float MapMesh::get_repeat_proportion() const { + return repeat_proportion; +} + +void MapMesh::set_subdivide_width(const int divisions) { + subdivide_w = divisions > 0 ? divisions : 0; + _request_update(); +} + +int MapMesh::get_subdivide_width() const { + return subdivide_w; +} + +void MapMesh::set_subdivide_depth(const int divisions) { + subdivide_d = divisions > 0 ? divisions : 0; + _request_update(); +} + +int MapMesh::get_subdivide_depth() const { + return subdivide_d; +} + +AABB MapMesh::get_core_aabb() const { + const Vector3 size{ aspect_ratio, 0.0f, 1.0f }; + return AABB{ size * -0.5f, size }; +} + +bool MapMesh::is_valid_uv_coord(godot::Vector2 const& uv) const { + return 0.0f <= uv.y && uv.y <= 1.0f; +} + +Array MapMesh::_create_mesh_array() const { + Array arr; + arr.resize(Mesh::ARRAY_MAX); + + const int vertex_count = (subdivide_w + 2) * (subdivide_d + 2); + const int indice_count = (subdivide_w + 1) * (subdivide_d + 1) * 6; + + PackedVector3Array points; + PackedVector3Array normals; + PackedFloat32Array tangents; + PackedVector2Array uvs; + PackedInt32Array indices; + + points.resize(vertex_count); + normals.resize(vertex_count); + tangents.resize(vertex_count * 4); + uvs.resize(vertex_count); + indices.resize(indice_count); + + static const Vector3 normal{ 0.0f, 1.0f, 0.0f }; + const Size2 uv_size{ 1.0f + 2.0f * repeat_proportion, 1.0f }; + const Size2 size{ aspect_ratio * uv_size.x, uv_size.y }, start_pos = size * -0.5f; + + int point_index = 0, thisrow = 0, prevrow = 0, indice_index = 0; + Vector2 subdivide_step{ 1.0f / (subdivide_w + 1.0f) , 1.0f / (subdivide_d + 1.0f) }; + Vector3 point{ 0.0f, 0.0f, start_pos.y }; + Vector2 point_step = subdivide_step * size; + Vector2 uv{}, uv_step = subdivide_step * uv_size; + + for (int j = 0; j <= subdivide_d + 1; ++j) { + point.x = start_pos.x; + uv.x = -repeat_proportion; + + for (int i = 0; i <= subdivide_w + 1; ++i) { + + points[point_index] = point; + normals[point_index] = normal; + tangents[point_index * 4 + 0] = 1.0f; + tangents[point_index * 4 + 1] = 0.0f; + tangents[point_index * 4 + 2] = 0.0f; + tangents[point_index * 4 + 3] = 1.0f; + uvs[point_index] = uv; + point_index++; + + if (i > 0 && j > 0) { + indices[indice_index + 0] = prevrow + i - 1; + indices[indice_index + 1] = prevrow + i; + indices[indice_index + 2] = thisrow + i - 1; + indices[indice_index + 3] = prevrow + i; + indices[indice_index + 4] = thisrow + i; + indices[indice_index + 5] = thisrow + i - 1; + indice_index += 6; + } + + point.x += point_step.x; + uv.x += uv_step.x; + } + + point.z += point_step.y; + uv.y += uv_step.y; + prevrow = thisrow; + thisrow = point_index; + } + + arr[Mesh::ARRAY_VERTEX] = points; + arr[Mesh::ARRAY_NORMAL] = normals; + arr[Mesh::ARRAY_TANGENT] = tangents; + arr[Mesh::ARRAY_TEX_UV] = uvs; + arr[Mesh::ARRAY_INDEX] = indices; + + return arr; +} diff --git a/extension/src/MapMesh.hpp b/extension/src/MapMesh.hpp new file mode 100644 index 0000000..d8727cf --- /dev/null +++ b/extension/src/MapMesh.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace OpenVic2 { + class MapMesh : public godot::PrimitiveMesh { + GDCLASS(MapMesh, godot::PrimitiveMesh) + + float aspect_ratio = 2.0f, repeat_proportion = 0.5f; + int subdivide_w = 0, subdivide_d = 0; + + protected: + static void _bind_methods(); + void _request_update(); + + public: + void set_aspect_ratio(const float ratio); + float get_aspect_ratio() const; + + void set_repeat_proportion(const float proportion); + float get_repeat_proportion() const; + + void set_subdivide_width(const int divisions); + int get_subdivide_width() const; + + void set_subdivide_depth(const int divisions); + int get_subdivide_depth() const; + + godot::AABB get_core_aabb() const; + bool is_valid_uv_coord(godot::Vector2 const& uv) const; + + godot::Array _create_mesh_array() const override; + }; +} diff --git a/extension/src/MapSingleton.cpp b/extension/src/MapSingleton.cpp new file mode 100644 index 0000000..0f5fe7c --- /dev/null +++ b/extension/src/MapSingleton.cpp @@ -0,0 +1,256 @@ +#include "MapSingleton.hpp" + +#include +#include +#include + +using namespace godot; +using namespace OpenVic2; + +MapSingleton* MapSingleton::singleton = nullptr; + +void MapSingleton::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &MapSingleton::load_province_identifier_file); + ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &MapSingleton::load_province_shape_file); + ClassDB::bind_method(D_METHOD("get_province_identifier_from_pixel_coords", "coords"), &MapSingleton::get_province_identifier_from_pixel_coords); + ClassDB::bind_method(D_METHOD("get_width"), &MapSingleton::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &MapSingleton::get_height); + ClassDB::bind_method(D_METHOD("get_province_index_image"), &MapSingleton::get_province_index_image); + ClassDB::bind_method(D_METHOD("get_province_colour_image"), &MapSingleton::get_province_colour_image); +} + +MapSingleton* MapSingleton::get_singleton() { + return singleton; +} + +MapSingleton::MapSingleton() { + ERR_FAIL_COND(singleton != nullptr); + singleton = this; +} + +MapSingleton::~MapSingleton() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + +Error MapSingleton::load_province_identifier_file(String const& file_path) { + UtilityFunctions::print("Loading identifier file: ", file_path); + Ref 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 province identifier file: ", file_path); + return err == OK ? FAILED : err; + } + String json_string = file->get_as_text(); + Ref json; + json.instantiate(); + err = json->parse(json_string); + if (err) { + UtilityFunctions::push_error("Failed to parse province identifier file as JSON: ", file_path, + "\nError at line ", json->get_error_line(), ": ", json->get_error_message()); + return err; + } + Variant json_var = json->get_data(); + Variant::Type type = json_var.get_type(); + if (type != Variant::DICTIONARY) { + UtilityFunctions::push_error("Invalid province identifier JSON: root has type ", + Variant::get_type_name(type), " (expected Dictionary)"); + return FAILED; + } + Dictionary prov_dict = json_var; + Array prov_identifiers = prov_dict.keys(); + for (int idx = 0; idx < prov_identifiers.size(); ++idx) { + String const& identifier = prov_identifiers[idx]; + Variant const& colour_var = prov_dict[identifier]; + if (identifier.is_empty()) { + UtilityFunctions::push_error("Empty province identifier with colour: ", colour_var); + err = FAILED; + continue; + } + static const String prov_prefix = "prov_"; + if (!identifier.begins_with(prov_prefix)) + UtilityFunctions::push_warning("Province identifier missing prefix: ", identifier); + type = colour_var.get_type(); + Province::colour_t colour = Province::NULL_COLOUR; + if (type == Variant::ARRAY) { + Array colour_array = colour_var; + if (colour_array.size() == 3) { + for (int jdx = 0; jdx < 3; ++jdx) { + Variant var = colour_array[jdx]; + if (var.get_type() != Variant::FLOAT) { + colour = Province::NULL_COLOUR; + break; + } + double colour_double = var; + if (std::trunc(colour_double) != colour_double) { + colour = Province::NULL_COLOUR; + break; + } + int64_t colour_int = static_cast(colour_double); + if (colour_int < 0 || colour_int > 255) { + colour = Province::NULL_COLOUR; + break; + } + colour = (colour << 8) | colour_int; + } + } + } else if (type == Variant::STRING) { + String colour_string = colour_var; + if (colour_string.is_valid_hex_number()) { + int64_t colour_int = colour_string.hex_to_int(); + if (0 <= colour_int && colour_int <= 0xFFFFFF) + colour = colour_int; + } + } + if (colour == Province::NULL_COLOUR) { + UtilityFunctions::push_error("Invalid province identifier colour for ", identifier, ": ", colour_var); + err = FAILED; + continue; + } + std::string error_message; + if (!map.add_province(identifier.utf8().get_data(), colour, error_message)) { + UtilityFunctions::push_error(error_message.c_str()); + err = FAILED; + } + } + map.lock_provinces(); + return err; +} + +static Province::colour_t colour_at(PackedByteArray const& colour_data_array, int32_t idx) { + return (colour_data_array[idx * 3] << 16) | (colour_data_array[idx * 3 + 1] << 8) | colour_data_array[idx * 3 + 2]; +} + +Error MapSingleton::load_province_shape_file(String const& file_path) { + if (province_shape_image.is_valid()) { + UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); + return FAILED; + } + province_shape_image.instantiate(); + Error err = province_shape_image->load(file_path); + if (err != OK) { + UtilityFunctions::push_error("Failed to load province shape file: ", file_path); + province_shape_image.unref(); + return err; + } + width = province_shape_image->get_width(); + height = province_shape_image->get_height(); + if (width < 1 || height < 1) { + UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); + err = FAILED; + } + static const Image::Format expected_format = Image::FORMAT_RGB8; + Image::Format format = province_shape_image->get_format(); + if (format != expected_format) { + UtilityFunctions::push_error("Invalid format (", format, ", should be ", expected_format, ") for province shape file: ", file_path); + err = FAILED; + } + if (err) { + province_shape_image.unref(); + return err; + } + + std::vector province_checklist(map.get_province_count()); + + PackedByteArray shape_data_array = province_shape_image->get_data(), index_data_array; + index_data_array.resize(width * height * sizeof(Province::index_t)); + Province::index_t* index_data = reinterpret_cast(index_data_array.ptrw()); + + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + const int32_t idx = x + y * width; + const Province::colour_t colour = colour_at(shape_data_array, idx); + if (colour == Province::NULL_COLOUR) { + index_data[idx] = Province::NULL_INDEX; + continue; + } + if (x > 0) { + const int32_t jdx = idx - 1; + if (colour_at(shape_data_array, jdx) == colour) { + index_data[idx] = index_data[jdx]; + continue; + } + } + if (y > 0) { + const int32_t jdx = idx - width; + if (colour_at(shape_data_array, jdx) == colour) { + index_data[idx] = index_data[jdx]; + continue; + } + } + const Province* province = map.get_province_by_colour(colour); + if (province) { + Province::index_t index = province->get_index(); + index_data[idx] = index; + province_checklist[index - 1] = true; + continue; + } + UtilityFunctions::push_error("Unrecognised province colour ", Province::colour_to_hex_string(colour).c_str(), " at (", x, ", ", y, ")"); + err = FAILED; + index_data[idx] = Province::NULL_INDEX; + } + } + + for (size_t idx = 0; idx < province_checklist.size(); ++idx) { + if (!province_checklist[idx]) { + Province* province = map.get_province_by_index(idx + 1); + if (province) UtilityFunctions::push_error("Province missing from shape image: ", province->to_string().c_str()); + else UtilityFunctions::push_error("Province missing for index: ", static_cast(idx + 1)); + err = FAILED; + } + } + + province_index_image = Image::create_from_data(width, height, false, Image::FORMAT_RG8, index_data_array); + if (province_index_image.is_null()) { + UtilityFunctions::push_error("Failed to create province ID image"); + err = FAILED; + } + + PackedByteArray colour_data_array; + colour_data_array.resize((Province::MAX_INDEX + 1) * 3); + for (size_t idx = 1; idx <= map.get_province_count(); ++idx) { + const Province* province = map.get_province_by_index(idx); + if (province) { + const Province::colour_t colour = province->get_colour(); + colour_data_array[3 * idx + 0] = (colour >> 16) & 0xFF; + colour_data_array[3 * idx + 1] = (colour >> 8) & 0xFF; + colour_data_array[3 * idx + 2] = colour & 0xFF; + } else UtilityFunctions::push_error("Missing province at index ", static_cast(idx)); + } + static const int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); + province_colour_image = Image::create_from_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, false, Image::FORMAT_RGB8, colour_data_array); + if (province_colour_image.is_null()) { + UtilityFunctions::push_error("Failed to create province colour image"); + err = FAILED; + } + + return err; +} + +String MapSingleton::get_province_identifier_from_pixel_coords(Vector2i const& coords) { + if (province_index_image.is_valid()) { + const PackedByteArray index_data_array = province_index_image->get_data(); + const Province::index_t* index_data = reinterpret_cast(index_data_array.ptr()); + const int32_t x_mod_w = UtilityFunctions::posmod(coords.x, width); + const int32_t y_mod_h = UtilityFunctions::posmod(coords.y, height); + const Province* province = map.get_province_by_index(index_data[x_mod_w + y_mod_h * width]); + if (province) return province->get_identifier().c_str(); + } + return String{}; +} + +int32_t MapSingleton::get_width() const { + return width; +} + +int32_t MapSingleton::get_height() const { + return height; +} + +Ref MapSingleton::get_province_index_image() const { + return province_index_image; +} + +Ref MapSingleton::get_province_colour_image() const { + return province_colour_image; +} diff --git a/extension/src/MapSingleton.hpp b/extension/src/MapSingleton.hpp new file mode 100644 index 0000000..71761cd --- /dev/null +++ b/extension/src/MapSingleton.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include "openvic2/Map.hpp" + +namespace OpenVic2 { + class MapSingleton : public godot::Object { + + GDCLASS(MapSingleton, godot::Object) + + static MapSingleton* singleton; + + godot::Ref province_shape_image, province_index_image, province_colour_image; + int32_t width = 0, height = 0; + Map map; + + protected: + static void _bind_methods(); + + public: + static MapSingleton* get_singleton(); + + MapSingleton(); + ~MapSingleton(); + + godot::Error load_province_identifier_file(godot::String const& file_path); + godot::Error load_province_shape_file(godot::String const& file_path); + godot::String get_province_identifier_from_pixel_coords(godot::Vector2i const& coords); + int32_t get_width() const; + int32_t get_height() const; + godot::Ref get_province_index_image() const; + godot::Ref get_province_colour_image() const; + }; +} diff --git a/extension/src/TestSingleton.cpp b/extension/src/TestSingleton.cpp index 0855a30..d9e2b03 100644 --- a/extension/src/TestSingleton.cpp +++ b/extension/src/TestSingleton.cpp @@ -6,14 +6,14 @@ using namespace godot; using namespace OpenVic2; -TestSingleton *TestSingleton::singleton = nullptr; +TestSingleton* TestSingleton::singleton = nullptr; void TestSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("hello_singleton"), &TestSingleton::hello_singleton); } -TestSingleton *TestSingleton::get_singleton() +TestSingleton* TestSingleton::get_singleton() { return singleton; } diff --git a/extension/src/TestSingleton.hpp b/extension/src/TestSingleton.hpp index de27589..d140516 100644 --- a/extension/src/TestSingleton.hpp +++ b/extension/src/TestSingleton.hpp @@ -8,13 +8,13 @@ namespace OpenVic2 { { GDCLASS(TestSingleton, godot::Object) - static TestSingleton *singleton; + static TestSingleton* singleton; protected: static void _bind_methods(); public: - static TestSingleton *get_singleton(); + static TestSingleton* get_singleton(); TestSingleton(); ~TestSingleton(); diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp new file mode 100644 index 0000000..d980b88 --- /dev/null +++ b/extension/src/openvic2/Map.cpp @@ -0,0 +1,89 @@ +#include "Map.hpp" + +#include +#include +#include + +using namespace OpenVic2; + +Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : + index(new_index), identifier(new_identifier), colour(new_colour) { + assert(index != NULL_INDEX); + assert(!identifier.empty()); + assert(colour != NULL_COLOUR); +} + +std::string Province::colour_to_hex_string(colour_t colour) { + std::ostringstream stream; + stream << std::hex << std::setfill('0') << std::setw(6) << colour; + return stream.str(); +} + +Province::index_t Province::get_index() const { + return index; +} + +std::string const& Province::get_identifier() const { + return identifier; +} + +Province::colour_t Province::get_colour() const { + return colour; +} + +std::string Province::to_string() const { + return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")"; +} + +bool Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) { + if (provinces_locked) { + error_message = "The map's province list has already been locked!"; + return false; + } + if (provinces.size() >= Province::MAX_INDEX) { + error_message = "The map's province list is full - there can be at most " + std::to_string(Province::MAX_INDEX) + " provinces"; + return false; + } + if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { + error_message = "Invalid province colour: " + Province::colour_to_hex_string(colour); + return false; + } + Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; + for (Province const& province : provinces) { + if (province.identifier == identifier) { + error_message = "Duplicate province identifiers: " + province.to_string() + " and " + new_province.to_string(); + return false; + } + if (province.colour == colour) { + error_message = "Duplicate province colours: " + province.to_string() + " and " + new_province.to_string(); + return false; + } + } + provinces.push_back(new_province); + error_message = "Added province: " + new_province.to_string(); + return true; +} + +void Map::lock_provinces() { + provinces_locked = true; +} + +size_t Map::get_province_count() const { + return provinces.size(); +} + +Province* Map::get_province_by_index(Province::index_t index) { + return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; +} + +Province* Map::get_province_by_identifier(std::string const& identifier) { + for (Province& province : provinces) + if (province.identifier == identifier) return &province; + return nullptr; +} + +Province* Map::get_province_by_colour(Province::colour_t colour) { + for (Province& province : provinces) + if (province.colour == colour) return &province; + return nullptr; +} diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp new file mode 100644 index 0000000..365d78b --- /dev/null +++ b/extension/src/openvic2/Map.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +namespace OpenVic2 { + + struct Province { + using colour_t = uint32_t; + using index_t = uint16_t; + friend struct Map; + static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; + static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; + private: + index_t index; + std::string identifier; + colour_t colour; + + Province(index_t index, std::string const& identifier, colour_t colour); + public: + static std::string colour_to_hex_string(colour_t colour); + + index_t get_index() const; + std::string const& get_identifier() const; + colour_t get_colour() const; + std::string to_string() const; + }; + + struct Map { + private: + std::vector provinces; + bool provinces_locked = false; + + public: + bool add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message); + void lock_provinces(); + size_t get_province_count() const; + + Province* get_province_by_index(Province::index_t index); + Province* get_province_by_identifier(std::string const& identifier); + Province* get_province_by_colour(Province::colour_t colour); + }; + +} diff --git a/extension/src/register_types.cpp b/extension/src/register_types.cpp index d1613a5..16e59b2 100644 --- a/extension/src/register_types.cpp +++ b/extension/src/register_types.cpp @@ -9,6 +9,8 @@ #include "Simulation.hpp" #include "Checksum.hpp" #include "LoadLocalisation.hpp" +#include "MapSingleton.hpp" +#include "MapMesh.hpp" using namespace godot; using namespace OpenVic2; @@ -17,9 +19,9 @@ static TestSingleton* _test_singleton; static Simulation* _simulation; static Checksum* _checksum; static LoadLocalisation* _load_localisation; +static MapSingleton* _map_singleton; -void initialize_openvic2_types(ModuleInitializationLevel p_level) -{ +void initialize_openvic2_types(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } @@ -40,6 +42,11 @@ void initialize_openvic2_types(ModuleInitializationLevel p_level) _load_localisation = memnew(LoadLocalisation); Engine::get_singleton()->register_singleton("LoadLocalisation", LoadLocalisation::get_singleton()); + ClassDB::register_class(); + _map_singleton = memnew(MapSingleton); + Engine::get_singleton()->register_singleton("MapSingleton", MapSingleton::get_singleton()); + + ClassDB::register_class(); } void uninitialize_openvic2_types(ModuleInitializationLevel p_level) { @@ -58,15 +65,16 @@ void uninitialize_openvic2_types(ModuleInitializationLevel p_level) { Engine::get_singleton()->unregister_singleton("LoadLocalisation"); memdelete(_load_localisation); + + Engine::get_singleton()->unregister_singleton("MapSingleton"); + memdelete(_map_singleton); } -extern "C" -{ +extern "C" { // Initialization. - GDExtensionBool GDE_EXPORT openvic2_library_init(const GDExtensionInterface *p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) - { + GDExtensionBool GDE_EXPORT openvic2_library_init(const GDExtensionInterface* p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization* r_initialization) { GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); init_obj.register_initializer(initialize_openvic2_types); diff --git a/game/common/map/provinces.json b/game/common/map/provinces.json new file mode 100644 index 0000000..66de29b --- /dev/null +++ b/game/common/map/provinces.json @@ -0,0 +1,9 @@ +{ + "prov_britain": [150, 0, 0], + "prov_ireland": [23, 147, 31], + "prov_iceland": "343D91", + "prov_cuba": "1E29FF", + "prov_madagascar": "790091", + "prov_ceylon": "FF6A00", + "prov_formosa": "82B1FF" +} diff --git a/game/common/map/provinces.png b/game/common/map/provinces.png new file mode 100644 index 0000000..68bf528 Binary files /dev/null and b/game/common/map/provinces.png differ diff --git a/game/common/map/provinces.png.import b/game/common/map/provinces.png.import new file mode 100644 index 0000000..8dd0c09 --- /dev/null +++ b/game/common/map/provinces.png.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/game/common/map/terrain/terrain.png b/game/common/map/terrain/terrain.png new file mode 100644 index 0000000..6d36dee Binary files /dev/null and b/game/common/map/terrain/terrain.png differ diff --git a/game/common/map/terrain/terrain.png.import b/game/common/map/terrain/terrain.png.import new file mode 100644 index 0000000..56ba5dc --- /dev/null +++ b/game/common/map/terrain/terrain.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cmw0pvjthnn8c" +path="res://.godot/imported/terrain.png-c443b8a709ca7acc4b3bb3df1d3095a9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://common/map/terrain/terrain.png" +dest_files=["res://.godot/imported/terrain.png-c443b8a709ca7acc4b3bb3df1d3095a9.ctex"] + +[params] + +compress/mode=3 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv index 27a0858..b483662 100644 --- a/game/localisation/en_GB/menus.csv +++ b/game/localisation/en_GB/menus.csv @@ -1,3 +1,4 @@ + ,, Main Menu MAINMENU_TITLE,OpenVic2 MAINMENU_NEW_GAME,New Game diff --git a/game/localisation/en_GB/provinces.csv b/game/localisation/en_GB/provinces.csv new file mode 100644 index 0000000..3b47955 --- /dev/null +++ b/game/localisation/en_GB/provinces.csv @@ -0,0 +1,9 @@ + +,, Test Provinces +prov_britain_NAME,Britain +prov_ireland_NAME,Ireland +prov_iceland_NAME,Iceland +prov_cuba_NAME,Cuba +prov_madagascar_NAME,Madagascar +prov_ceylon_NAME,Ceylon +prov_formosa_NAME,Formosa diff --git a/game/localisation/en_GB/provinces.csv.import b/game/localisation/en_GB/provinces.csv.import new file mode 100644 index 0000000..8dd0c09 --- /dev/null +++ b/game/localisation/en_GB/provinces.csv.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/game/project.godot b/game/project.godot index 363bbc1..fa2871f 100644 --- a/game/project.godot +++ b/game/project.godot @@ -44,6 +44,55 @@ enabled=PackedStringArray("res://addons/keychain/plugin.cfg", "res://addons/open theme/custom="res://theme/default_theme.tres" +[input] + +map_north={ +"deadzone": 0.5, +"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":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, 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":87,"physical_keycode":0,"key_label":0,"unicode":119,"echo":false,"script":null) +] +} +map_east={ +"deadzone": 0.5, +"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":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, 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":68,"physical_keycode":0,"key_label":0,"unicode":100,"echo":false,"script":null) +] +} +map_south={ +"deadzone": 0.5, +"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":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, 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":83,"physical_keycode":0,"key_label":0,"unicode":115,"echo":false,"script":null) +] +} +map_west={ +"deadzone": 0.5, +"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":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, 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":65,"physical_keycode":0,"key_label":0,"unicode":97,"echo":false,"script":null) +] +} +map_zoomin={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(174, 17),"global_position":Vector2(180, 80),"factor":1.0,"button_index":4,"pressed":true,"double_click":false,"script":null) +, 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":81,"physical_keycode":0,"key_label":0,"unicode":113,"echo":false,"script":null) +] +} +map_zoomout={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(325, 24),"global_position":Vector2(331, 87),"factor":1.0,"button_index":5,"pressed":true,"double_click":false,"script":null) +, 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":69,"physical_keycode":0,"key_label":0,"unicode":101,"echo":false,"script":null) +] +} +map_drag={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"pressed":false,"double_click":false,"script":null) +] +} +map_click={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"pressed":false,"double_click":false,"script":null) +] +} + [internationalization] locale/translation_remaps={} diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index 25a185f..040cb06 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -2,3 +2,12 @@ extends Node var Options = preload("Events/Options.gd").new() var Localisation = preload("Events/Localisation.gd").new() + +const _province_identifier_file : String = "res://common/map/provinces.json" +const _province_shape_file : String = "res://common/map/provinces.png" + +func _ready(): + if MapSingleton.load_province_identifier_file(_province_identifier_file) != OK: + push_error("Failed to load province identifiers") + if MapSingleton.load_province_shape_file(_province_shape_file) != OK: + push_error("Failed to load province shapes") diff --git a/game/src/GameSession/GameSession.gd b/game/src/GameSession/GameSession.gd index 0d69bf2..38eaba1 100644 --- a/game/src/GameSession/GameSession.gd +++ b/game/src/GameSession/GameSession.gd @@ -1,4 +1,4 @@ -extends Control +extends Node @export var _game_session_menu : Control diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index f984daf..390040e 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -1,23 +1,20 @@ -[gd_scene load_steps=4 format=3 uid="uid://bgnupcshe1m7r"] +[gd_scene load_steps=6 format=3 uid="uid://bgnupcshe1m7r"] [ext_resource type="Script" path="res://src/GameSession/GameSession.gd" id="1_eklvp"] [ext_resource type="PackedScene" uid="uid://g524p8lr574w" path="res://src/GameSession/MapControlPanel.tscn" id="3_afh6d"] [ext_resource type="PackedScene" uid="uid://dvdynl6eir40o" path="res://src/GameSession/GameSessionMenu.tscn" id="3_bvmqh"] +[ext_resource type="PackedScene" uid="uid://dkehmdnuxih2r" path="res://src/GameSession/MapView.tscn" id="4_xkg5j"] +[ext_resource type="PackedScene" uid="uid://byq323jbel48u" path="res://src/GameSession/ProvinceOverviewPanel.tscn" id="5_osjnn"] -[node name="GameSession" type="Control" node_paths=PackedStringArray("_game_session_menu")] +[node name="GameSession" type="Node" node_paths=PackedStringArray("_game_session_menu")] editor_description = "SS-102" -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 script = ExtResource("1_eklvp") _game_session_menu = NodePath("GameSessionMenu") +[node name="MapView" parent="." instance=ExtResource("4_xkg5j")] + [node name="GameSessionMenu" parent="." instance=ExtResource("3_bvmqh")] visible = false -layout_mode = 1 anchors_preset = 8 anchor_left = 0.5 anchor_top = 0.5 @@ -27,7 +24,6 @@ grow_horizontal = 2 grow_vertical = 2 [node name="MapControlPanel" parent="." instance=ExtResource("3_afh6d")] -layout_mode = 1 anchors_preset = 3 anchor_left = 1.0 anchor_top = 1.0 @@ -36,5 +32,13 @@ anchor_bottom = 1.0 grow_horizontal = 0 grow_vertical = 0 +[node name="ProvinceOverviewPanel" parent="." instance=ExtResource("5_osjnn")] +anchors_preset = -1 +anchor_top = 0.583333 +anchor_right = 0.15625 +offset_top = 0.0 +offset_right = 0.0 + +[connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] [connection signal="close_button_pressed" from="GameSessionMenu" to="." method="_on_game_session_menu_close_button_pressed"] [connection signal="game_session_menu_button_pressed" from="MapControlPanel" to="." method="_on_game_session_menu_button_pressed"] diff --git a/game/src/GameSession/MapControlPanel.tscn b/game/src/GameSession/MapControlPanel.tscn index 71d43e7..2a0c971 100644 --- a/game/src/GameSession/MapControlPanel.tscn +++ b/game/src/GameSession/MapControlPanel.tscn @@ -1,7 +1,13 @@ -[gd_scene load_steps=2 format=3 uid="uid://g524p8lr574w"] +[gd_scene load_steps=4 format=3 uid="uid://g524p8lr574w"] [ext_resource type="Script" path="res://src/GameSession/MapControlPanel.gd" id="1_ign64"] +[sub_resource type="InputEventAction" id="InputEventAction_5nck3"] +action = &"ui_cancel" + +[sub_resource type="Shortcut" id="Shortcut_fc1tk"] +events = [SubResource("InputEventAction_5nck3")] + [node name="PanelContainer" type="PanelContainer"] editor_description = "SS-103" script = ExtResource("1_ign64") @@ -27,6 +33,7 @@ layout_mode = 2 [node name="GameSessionMenuButton" type="Button" parent="HBoxContainer/AuxiliaryPanel"] editor_description = "UI-9" layout_mode = 2 +shortcut = SubResource("Shortcut_fc1tk") text = "ESC" [connection signal="pressed" from="HBoxContainer/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd new file mode 100644 index 0000000..faf90e8 --- /dev/null +++ b/game/src/GameSession/MapView.gd @@ -0,0 +1,185 @@ +extends Node3D + +signal province_selected(identifier : String) + +const _action_north : StringName = &"map_north" +const _action_east : StringName = &"map_east" +const _action_south : StringName = &"map_south" +const _action_west : StringName = &"map_west" +const _action_zoomin : StringName = &"map_zoomin" +const _action_zoomout : StringName = &"map_zoomout" +const _action_drag : StringName = &"map_drag" +const _action_click : StringName = &"map_click" + +const _shader_param_province_index : StringName = &"province_index_tex" +const _shader_param_province_colour : StringName = &"province_colour_tex" +const _shader_param_hover_pos : StringName = &"hover_pos" +const _shader_param_selected_pos : StringName = &"selected_pos" + +@export var _camera : Camera3D + +@export var _cardinal_move_speed : float = 1.0 +@export var _edge_move_threshold: float = 0.15 +@export var _edge_move_speed: float = 2.5 +var _drag_anchor : Vector2 +var _drag_active : bool = false + +@export var _zoom_target_min : float = 0.2 +@export var _zoom_target_max : float = 5.0 +@export var _zoom_target_step : float = 0.1 +@export var _zoom_epsilon : float = _zoom_target_step * 0.1 +@export var _zoom_speed : float = 5.0 +@export var _zoom_target : float = 1.0: + get: return _zoom_target + set(v): _zoom_target = clamp(v, _zoom_target_min, _zoom_target_max) + +@export var _map_mesh_instance : MeshInstance3D +var _map_mesh : MapMesh +var _map_shader_material : ShaderMaterial +var _map_image_size : Vector2 +var _map_province_index_image : Image +var _map_mesh_corner : Vector2 +var _map_mesh_dims : Vector2 + +var _mouse_pos_viewport : Vector2 = Vector2(0.5, 0.5) +var _mouse_pos_map : Vector2 = Vector2(0.5, 0.5) + +func _ready(): + if _camera == null: + push_error("MapView's _camera variable hasn't been set!") + return + if _map_mesh_instance == null: + push_error("MapView's _map_mesh variable hasn't been set!") + return + if not _map_mesh_instance.mesh is MapMesh: + push_error("Invalid map mesh class: ", _map_mesh_instance.mesh.get_class(), "(expected MapMesh)") + return + _map_mesh = _map_mesh_instance.mesh + + # Set map mesh size and get bounds + _map_image_size = Vector2(Vector2i(MapSingleton.get_width(), MapSingleton.get_height())) + _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y + var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform + _map_mesh_corner = Vector2( + min(map_mesh_aabb.position.x, map_mesh_aabb.end.x), + min(map_mesh_aabb.position.z, map_mesh_aabb.end.z) + ) + _map_mesh_dims = abs(Vector2( + map_mesh_aabb.position.x - map_mesh_aabb.end.x, + map_mesh_aabb.position.z - map_mesh_aabb.end.z + )) + + var map_material = _map_mesh_instance.get_active_material(0) + if map_material == null: + push_error("Map mesh is missing material!") + return + if not map_material is ShaderMaterial: + push_error("Invalid map mesh material class: ", map_material.get_class()) + return + _map_shader_material = map_material + # Province index texture + _map_province_index_image = MapSingleton.get_province_index_image() + if _map_province_index_image == null: + push_error("Failed to get province index image!") + return + var province_index_texture := ImageTexture.create_from_image(_map_province_index_image) + _map_shader_material.set_shader_parameter(_shader_param_province_index, province_index_texture) + # Province colour texture + var province_colour_image = MapSingleton.get_province_colour_image() + if province_colour_image == null: + push_error("Failed to get province colour image!") + return + var province_colour_texture := ImageTexture.create_from_image(province_colour_image) + _map_shader_material.set_shader_parameter(_shader_param_province_colour, province_colour_texture) + +func _unhandled_input(event : InputEvent): + if event.is_action_pressed(_action_click): + # Check if the mouse is outside of bounds + if _map_mesh.is_valid_uv_coord(_mouse_pos_map): + _map_shader_material.set_shader_parameter(_shader_param_selected_pos, _mouse_pos_map) + var mouse_pixel_pos := Vector2i(_mouse_pos_map * _map_image_size) + var province_identifier := MapSingleton.get_province_identifier_from_pixel_coords(mouse_pixel_pos) + province_selected.emit(province_identifier) + elif event.is_action_pressed(_action_drag): + if _drag_active: + push_warning("Drag being activated while already active!") + _drag_active = true + _drag_anchor = _mouse_pos_map + elif event.is_action_released(_action_drag): + if not _drag_active: + push_warning("Drag being deactivated while already not active!") + _drag_active = false + elif event.is_action_pressed(_action_zoomin, true): + _zoom_target -= _zoom_target_step + elif event.is_action_pressed(_action_zoomout, true): + _zoom_target += _zoom_target_step + +func _physics_process(delta : float): + _mouse_pos_viewport = get_viewport().get_mouse_position() + # Process movement + _movement_process(delta) + # Keep within map bounds + _clamp_over_map() + # Process zooming + _zoom_process(delta) + # Orient based on height + _update_orientation() + # Calculate where the mouse lies on the map + _update_mouse_map_position() + +func _movement_process(delta : float) -> void: + var direction : Vector2 + if _drag_active: + direction = (_drag_anchor - _mouse_pos_map) * _map_mesh_dims + else: + direction = _edge_scrolling_vector() + _cardinal_movement_vector() + # Scale movement speed with height + direction *= _camera.position.y * delta + _camera.position += Vector3(direction.x, 0, direction.y) + +func _edge_scrolling_vector() -> Vector2: + var viewport_dims := Vector2(Resolution.get_current_resolution()) + var mouse_vector := _mouse_pos_viewport / viewport_dims - Vector2(0.5, 0.5); + if pow(mouse_vector.x, 4) + pow(mouse_vector.y, 4) < pow(0.5 - _edge_move_threshold, 4): + mouse_vector *= 0 + return mouse_vector * _edge_move_speed + +func _cardinal_movement_vector() -> Vector2: + var move := Vector2( + float(Input.is_action_pressed(_action_east)) - float(Input.is_action_pressed(_action_west)), + float(Input.is_action_pressed(_action_south)) - float(Input.is_action_pressed(_action_north)) + ) + return move * _cardinal_move_speed + +func _clamp_over_map() -> void: + _camera.position.x = _map_mesh_corner.x + fposmod(_camera.position.x - _map_mesh_corner.x, _map_mesh_dims.x) + _camera.position.z = clamp(_camera.position.z, _map_mesh_corner.y, _map_mesh_corner.y + _map_mesh_dims.y) + +func _zoom_process(delta : float) -> void: + var height := _camera.position.y + var zoom := _zoom_target - height + height += zoom * _zoom_speed * delta + var new_zoom := _zoom_target - height + # Set to target if height is within _zoom_epsilon of it or has overshot past it + if abs(new_zoom) < _zoom_epsilon or sign(zoom) != sign(new_zoom): + height = _zoom_target + _camera.position.y = height + +func _update_orientation() -> void: + var dir := Vector3(0, -1, -exp(-_camera.position.y * 2.0 + 0.5)) + _camera.look_at(_camera.position + dir) + +func _update_mouse_map_position() -> void: + var ray_origin := _camera.project_ray_origin(_mouse_pos_viewport) + var ray_normal := _camera.project_ray_normal(_mouse_pos_viewport) + # Plane with normal (0,1,0) facing upwards, at a distance 0 from the origin + var intersection = Plane(0, 1, 0, 0).intersects_ray(ray_origin, ray_normal) + if typeof(intersection) == TYPE_VECTOR3: + var intersection_vec := intersection as Vector3 + # This loops both horizontally (good) and vertically (bad) + _mouse_pos_map = (Vector2(intersection_vec.x, intersection_vec.z) - _map_mesh_corner) / _map_mesh_dims + _map_shader_material.set_shader_parameter(_shader_param_hover_pos, _mouse_pos_map) + else: + # Normals parallel to the xz-plane could cause null intersections, + # but the camera's orientation should prevent such normals + push_error("Invalid intersection: ", intersection) diff --git a/game/src/GameSession/MapView.tscn b/game/src/GameSession/MapView.tscn new file mode 100644 index 0000000..4650acb --- /dev/null +++ b/game/src/GameSession/MapView.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=6 format=3 uid="uid://dkehmdnuxih2r"] + +[ext_resource type="Script" path="res://src/GameSession/MapView.gd" id="1_exccw"] +[ext_resource type="Shader" path="res://src/GameSession/TerrainMap.gdshader" id="1_upocn"] +[ext_resource type="Texture2D" uid="uid://cmw0pvjthnn8c" path="res://common/map/terrain/terrain.png" id="3_l8pnf"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_tayeg"] +render_priority = 0 +shader = ExtResource("1_upocn") +shader_parameter/hover_pos = Vector2(0.5, 0.5) +shader_parameter/selected_pos = Vector2(0.5, 0.5) +shader_parameter/terrain_tex = ExtResource("3_l8pnf") + +[sub_resource type="MapMesh" id="MapMesh_3gtsd"] + +[node name="MapView" type="Node3D" node_paths=PackedStringArray("_camera", "_map_mesh_instance")] +script = ExtResource("1_exccw") +_camera = NodePath("MapCamera") +_map_mesh_instance = NodePath("MapMeshInstance") + +[node name="MapCamera" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 1, 1) + +[node name="MapMeshInstance" type="MeshInstance3D" parent="."] +transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0) +material_override = SubResource("ShaderMaterial_tayeg") +mesh = SubResource("MapMesh_3gtsd") diff --git a/game/src/GameSession/ProvinceOverviewPanel.gd b/game/src/GameSession/ProvinceOverviewPanel.gd new file mode 100644 index 0000000..434f6b1 --- /dev/null +++ b/game/src/GameSession/ProvinceOverviewPanel.gd @@ -0,0 +1,22 @@ +extends Panel + +@export var _province_name_label : Label + +@export var province_identifier: String = "": + get: return province_identifier + set(v): + province_identifier = v + update_info() + +func _ready(): + update_info() + +func update_info() -> void: + _province_name_label.text = province_identifier + "_NAME" + visible = not province_identifier.is_empty() + +func _on_province_selected(identifier : String) -> void: + province_identifier = identifier + +func _on_button_pressed() -> void: + province_identifier = "" diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn new file mode 100644 index 0000000..e21b1c3 --- /dev/null +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=2 format=3 uid="uid://byq323jbel48u"] + +[ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] + +[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label")] +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +offset_top = -300.0 +offset_right = 200.0 +grow_vertical = 0 +script = ExtResource("1_3n8k5") +_province_name_label = NodePath("VBoxContainer/ProvinceName") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = -1 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 10.0 +offset_top = 5.0 +offset_right = -10.0 +offset_bottom = -5.0 + +[node name="ProvinceName" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "PROVINCE_NAME" +vertical_alignment = 1 + +[node name="Button" type="Button" parent="."] +custom_minimum_size = Vector2(30, 30) +layout_mode = 1 +anchors_preset = -1 +anchor_left = 0.85 +anchor_right = 1.0 +anchor_bottom = 0.103333 +grow_horizontal = 0 +text = "X" + +[connection signal="pressed" from="Button" to="." method="_on_button_pressed"] diff --git a/game/src/GameSession/TerrainMap.gdshader b/game/src/GameSession/TerrainMap.gdshader new file mode 100644 index 0000000..a6774fd --- /dev/null +++ b/game/src/GameSession/TerrainMap.gdshader @@ -0,0 +1,48 @@ +shader_type spatial; + +render_mode unshaded; + +// Cosmetic terrain texture +uniform sampler2D terrain_tex: source_color, repeat_enable, filter_linear; +// Province index texture +uniform sampler2D province_index_tex : repeat_enable, filter_nearest; +// Province colour texture +uniform sampler2D province_colour_tex: source_color, repeat_enable, filter_nearest; +// Position of the mouse over the map mesh in UV coords +uniform vec2 hover_pos; +// Position in UV coords of a pixel belonging to the currently selected province +uniform vec2 selected_pos; + +uvec2 vec2_to_uvec2(vec2 v) { + return uvec2(v * 255.0); +} + +uint uvec2_to_uint(uvec2 v) { + return (v.y << 8u) | v.x; +} + +uvec2 read_uvec2(sampler2D tex, vec2 uv) { + return vec2_to_uvec2(texture(tex, uv).rg); +} + +uint read_uint16(sampler2D tex, vec2 uv) { + return uvec2_to_uint(read_uvec2(tex, uv)); +} + +void fragment() { + uvec2 prov_idx_split = read_uvec2(province_index_tex, UV); + + uint prov_index = uvec2_to_uint(prov_idx_split); + uint hover_index = read_uint16(province_index_tex, hover_pos); + uint selected_index = read_uint16(province_index_tex, selected_pos); + + // Boost prov_colour's contribution if it matches hover_colour or selected_colour + float mix_val = float(prov_index == hover_index) * 0.3 + float(prov_index == selected_index) * 0.5; + // Don't mix if the province index is 0 + mix_val *= float(prov_index != 0u); + + vec3 terrain_colour = texture(terrain_tex, UV).rgb; + vec3 province_colour = texelFetch(province_colour_tex, ivec2(prov_idx_split), 0).rgb; + + ALBEDO = mix(terrain_colour, province_colour, mix_val); +} -- cgit v1.2.3-56-ga3b1 From 7241811bd8c9493b7b6c6480e8d63a5fb7f38e4e Mon Sep 17 00:00:00 2001 From: Gone2Daly <71726742+Gone2Daly@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:10:49 +0200 Subject: Add minimap for terrain map With accurate viewport shape display on minimap With Mapmode management With Region mapmode With Province mapmode With Index mapmode With Minimap single-click movement With Minimap drag-click movement --- extension/src/Checksum.hpp | 8 +- extension/src/LoadLocalisation.hpp | 1 - extension/src/MapMesh.cpp | 1 - extension/src/MapSingleton.cpp | 359 +++++++++++++++--------- extension/src/MapSingleton.hpp | 24 +- extension/src/Simulation.hpp | 6 +- extension/src/TestSingleton.hpp | 1 - extension/src/openvic2/Map.cpp | 283 ++++++++++++++++--- extension/src/openvic2/Map.hpp | 78 ++++- extension/src/openvic2/Province.cpp | 40 +++ extension/src/openvic2/Region.cpp | 26 ++ extension/src/openvic2/Types.hpp | 7 + extension/src/register_types.cpp | 7 +- extension/src/register_types.h | 2 +- game/art/terrain/terrain.png | Bin 0 -> 27542091 bytes game/art/terrain/terrain.png.import | 34 +++ game/art/ui/minimap.png | Bin 0 -> 122017 bytes game/art/ui/minimap.png.import | 34 +++ game/art/ui/minimap_frame.png | Bin 0 -> 1043 bytes game/art/ui/minimap_frame.png.import | 34 +++ game/common/map/regions.json | 6 + game/common/map/terrain/terrain.png | Bin 27542091 -> 0 bytes game/common/map/terrain/terrain.png.import | 34 --- game/localisation/en_GB/mapmodes.csv | 5 + game/localisation/en_GB/mapmodes.csv.import | 3 + game/src/Autoload/Events.gd | 5 + game/src/GameSession/GameSession.tscn | 9 +- game/src/GameSession/MapControlPanel.gd | 40 ++- game/src/GameSession/MapControlPanel.tscn | 36 ++- game/src/GameSession/MapView.gd | 160 ++++++++--- game/src/GameSession/MapView.tscn | 10 +- game/src/GameSession/Minimap.gd | 89 ++++++ game/src/GameSession/ProvinceOverviewPanel.tscn | 2 + game/src/GameSession/TerrainMap.gdshader | 13 +- 34 files changed, 1058 insertions(+), 299 deletions(-) create mode 100644 extension/src/openvic2/Province.cpp create mode 100644 extension/src/openvic2/Region.cpp create mode 100644 extension/src/openvic2/Types.hpp create mode 100644 game/art/terrain/terrain.png create mode 100644 game/art/terrain/terrain.png.import create mode 100644 game/art/ui/minimap.png create mode 100644 game/art/ui/minimap.png.import create mode 100644 game/art/ui/minimap_frame.png create mode 100644 game/art/ui/minimap_frame.png.import create mode 100644 game/common/map/regions.json delete mode 100644 game/common/map/terrain/terrain.png delete mode 100644 game/common/map/terrain/terrain.png.import create mode 100644 game/localisation/en_GB/mapmodes.csv create mode 100644 game/localisation/en_GB/mapmodes.csv.import create mode 100644 game/src/GameSession/Minimap.gd diff --git a/extension/src/Checksum.hpp b/extension/src/Checksum.hpp index ebdbd43..717910e 100644 --- a/extension/src/Checksum.hpp +++ b/extension/src/Checksum.hpp @@ -1,15 +1,13 @@ #pragma once -#include #include -#include namespace OpenVic2 { class Checksum : public godot::Object { GDCLASS(Checksum, godot::Object) //BEGIN BOILERPLATE - static Checksum* _checksum; + inline static Checksum* _checksum = nullptr; protected: static void _bind_methods() { @@ -33,6 +31,4 @@ namespace OpenVic2 { return godot::String("1234abcd"); } }; - - Checksum* Checksum::_checksum = nullptr; -} \ No newline at end of file +} diff --git a/extension/src/LoadLocalisation.hpp b/extension/src/LoadLocalisation.hpp index f54a025..49c0313 100644 --- a/extension/src/LoadLocalisation.hpp +++ b/extension/src/LoadLocalisation.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include namespace OpenVic2 { diff --git a/extension/src/MapMesh.cpp b/extension/src/MapMesh.cpp index f0fc819..91c7611 100644 --- a/extension/src/MapMesh.cpp +++ b/extension/src/MapMesh.cpp @@ -111,7 +111,6 @@ Array MapMesh::_create_mesh_array() const { uv.x = -repeat_proportion; for (int i = 0; i <= subdivide_w + 1; ++i) { - points[point_index] = point; normals[point_index] = normal; tangents[point_index * 4 + 0] = 1.0f; diff --git a/extension/src/MapSingleton.cpp b/extension/src/MapSingleton.cpp index 0f5fe7c..73cf522 100644 --- a/extension/src/MapSingleton.cpp +++ b/extension/src/MapSingleton.cpp @@ -11,21 +11,50 @@ MapSingleton* MapSingleton::singleton = nullptr; void MapSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &MapSingleton::load_province_identifier_file); + ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &MapSingleton::load_region_file); ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &MapSingleton::load_province_shape_file); - ClassDB::bind_method(D_METHOD("get_province_identifier_from_pixel_coords", "coords"), &MapSingleton::get_province_identifier_from_pixel_coords); + + ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &MapSingleton::get_province_index_from_uv_coords); + ClassDB::bind_method(D_METHOD("get_province_identifier_from_uv_coords", "coords"), &MapSingleton::get_province_identifier_from_uv_coords); ClassDB::bind_method(D_METHOD("get_width"), &MapSingleton::get_width); ClassDB::bind_method(D_METHOD("get_height"), &MapSingleton::get_height); ClassDB::bind_method(D_METHOD("get_province_index_image"), &MapSingleton::get_province_index_image); ClassDB::bind_method(D_METHOD("get_province_colour_image"), &MapSingleton::get_province_colour_image); + + ClassDB::bind_method(D_METHOD("update_colour_image"), &MapSingleton::update_colour_image); + ClassDB::bind_method(D_METHOD("get_mapmode_count"), &MapSingleton::get_mapmode_count); + ClassDB::bind_method(D_METHOD("get_mapmode_identifier", "index"), &MapSingleton::get_mapmode_identifier); + ClassDB::bind_method(D_METHOD("set_mapmode", "identifier"), &MapSingleton::set_mapmode); } MapSingleton* MapSingleton::get_singleton() { return singleton; } +/* REQUIREMENTS: + * MAP-21, MAP-25 + */ MapSingleton::MapSingleton() { ERR_FAIL_COND(singleton != nullptr); singleton = this; + + using mapmode_t = std::pair; + const std::vector mapmodes = { + { "mapmode_province", [](Map const&, Province const& province) -> Province::colour_t { return province.get_colour(); } }, + { "mapmode_region", [](Map const&, Province const& province) -> Province::colour_t { + Region const* region = province.get_region(); + if (region != nullptr) return region->get_provinces().front()->get_colour(); + return province.get_colour(); + } }, + { "mapmode_index", [](Map const& map, Province const& province) -> Province::colour_t { + const uint8_t f = float(province.get_index()) / float(map.get_province_count()) * 255.0f; + return (f << 16) | (f << 8) | f; + } } + }; + std::string error_message = ""; + for (mapmode_t mapmode : mapmodes) + if (map.add_mapmode(mapmode.first, mapmode.second, error_message) != SUCCESS) + UtilityFunctions::push_error(error_message.c_str()); } MapSingleton::~MapSingleton() { @@ -33,172 +62,171 @@ MapSingleton::~MapSingleton() { singleton = nullptr; } -Error MapSingleton::load_province_identifier_file(String const& file_path) { - UtilityFunctions::print("Loading identifier file: ", file_path); +Error MapSingleton::parse_json_dictionary_file(String const& file_description, String const& file_path, + String const& identifier_prefix, parse_json_entry_func_t parse_entry) const { + UtilityFunctions::print("Loading ", file_description, " file: ", file_path); Ref 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 province identifier file: ", file_path); + UtilityFunctions::push_error("Failed to load ", file_description, " file: ", file_path); return err == OK ? FAILED : err; } - String json_string = file->get_as_text(); + const String json_string = file->get_as_text(); Ref json; json.instantiate(); err = json->parse(json_string); - if (err) { - UtilityFunctions::push_error("Failed to parse province identifier file as JSON: ", file_path, + 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; } - Variant json_var = json->get_data(); - Variant::Type type = json_var.get_type(); + const Variant json_var = json->get_data(); + const Variant::Type type = json_var.get_type(); if (type != Variant::DICTIONARY) { - UtilityFunctions::push_error("Invalid province identifier JSON: root has type ", + UtilityFunctions::push_error("Invalid ", file_description, " JSON: root has type ", Variant::get_type_name(type), " (expected Dictionary)"); return FAILED; } - Dictionary prov_dict = json_var; - Array prov_identifiers = prov_dict.keys(); - for (int idx = 0; idx < prov_identifiers.size(); ++idx) { - String const& identifier = prov_identifiers[idx]; - Variant const& colour_var = prov_dict[identifier]; + const Dictionary dict = json_var; + const Array identifiers = dict.keys(); + for (int idx = 0; idx < identifiers.size(); ++idx) { + String const& identifier = identifiers[idx]; + Variant const& entry = dict[identifier]; if (identifier.is_empty()) { - UtilityFunctions::push_error("Empty province identifier with colour: ", colour_var); + UtilityFunctions::push_error("Empty identifier in ", file_description, " file with entry: ", entry); err = FAILED; continue; } - static const String prov_prefix = "prov_"; - if (!identifier.begins_with(prov_prefix)) - UtilityFunctions::push_warning("Province identifier missing prefix: ", identifier); - type = colour_var.get_type(); - Province::colour_t colour = Province::NULL_COLOUR; - if (type == Variant::ARRAY) { - Array colour_array = colour_var; - if (colour_array.size() == 3) { - for (int jdx = 0; jdx < 3; ++jdx) { - Variant var = colour_array[jdx]; - if (var.get_type() != Variant::FLOAT) { - colour = Province::NULL_COLOUR; - break; - } - double colour_double = var; - if (std::trunc(colour_double) != colour_double) { - colour = Province::NULL_COLOUR; - break; - } - int64_t colour_int = static_cast(colour_double); - if (colour_int < 0 || colour_int > 255) { - colour = Province::NULL_COLOUR; - break; - } - colour = (colour << 8) | colour_int; + 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; +} + +Error MapSingleton::_parse_province_identifier_entry(String const& identifier, Variant const& entry) { + const Variant::Type type = entry.get_type(); + Province::colour_t colour = Province::NULL_COLOUR; + if (type == Variant::ARRAY) { + const Array colour_array = entry; + if (colour_array.size() == 3) { + for (int jdx = 0; jdx < 3; ++jdx) { + const Variant var = colour_array[jdx]; + if (var.get_type() != Variant::FLOAT) { + colour = Province::NULL_COLOUR; + break; } - } - } else if (type == Variant::STRING) { - String colour_string = colour_var; - if (colour_string.is_valid_hex_number()) { - int64_t colour_int = colour_string.hex_to_int(); - if (0 <= colour_int && colour_int <= 0xFFFFFF) - colour = colour_int; + double colour_double = var; + if (std::trunc(colour_double) != colour_double) { + colour = Province::NULL_COLOUR; + break; + } + int64_t colour_int = static_cast(colour_double); + if (colour_int < 0 || colour_int > 255) { + colour = Province::NULL_COLOUR; + break; + } + colour = (colour << 8) | colour_int; } } - if (colour == Province::NULL_COLOUR) { - UtilityFunctions::push_error("Invalid province identifier colour for ", identifier, ": ", colour_var); - err = FAILED; - continue; - } - std::string error_message; - if (!map.add_province(identifier.utf8().get_data(), colour, error_message)) { - UtilityFunctions::push_error(error_message.c_str()); - err = FAILED; + } else if (type == Variant::STRING) { + String colour_string = entry; + if (colour_string.is_valid_hex_number()) { + int64_t colour_int = colour_string.hex_to_int(); + if (0 <= colour_int && colour_int <= 0xFFFFFF) + colour = colour_int; } + } else { + UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry); + return FAILED; } + std::string error_message = ""; + if (map.add_province(identifier.utf8().get_data(), colour, error_message) != SUCCESS) { + UtilityFunctions::push_error(error_message.c_str()); + return FAILED; + } + return OK; +} + +Error MapSingleton::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 this->_parse_province_identifier_entry(identifier, entry); + }); map.lock_provinces(); return err; } -static Province::colour_t colour_at(PackedByteArray const& colour_data_array, int32_t idx) { - return (colour_data_array[idx * 3] << 16) | (colour_data_array[idx * 3 + 1] << 8) | colour_data_array[idx * 3 + 2]; +Error MapSingleton::_parse_region_entry(String const& identifier, Variant const& entry) { + Error err = OK; + Variant::Type type = entry.get_type(); + std::vector province_identifiers; + if (type == Variant::ARRAY) { + const Array province_array = entry; + for (int64_t idx = 0; idx < province_array.size(); ++idx) { + const Variant province_var = province_array[idx]; + type = province_var.get_type(); + if (type == Variant::STRING) { + String province_string = province_var; + province_identifiers.push_back(province_string.utf8().get_data()); + } else { + UtilityFunctions::push_error("Invalid province identifier for region \"", identifier, "\": ", entry); + err = FAILED; + } + } + } + std::string error_message = ""; + if (map.add_region(identifier.utf8().get_data(), province_identifiers, error_message) != SUCCESS) { + UtilityFunctions::push_error(error_message.c_str()); + return FAILED; + } + return err; +} + +Error MapSingleton::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 this->_parse_region_entry(identifier, entry); + }); + map.lock_regions(); + return err; } Error MapSingleton::load_province_shape_file(String const& file_path) { - if (province_shape_image.is_valid()) { + if (province_index_image.is_valid()) { UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); return FAILED; } + Ref province_shape_image; province_shape_image.instantiate(); Error err = province_shape_image->load(file_path); if (err != OK) { UtilityFunctions::push_error("Failed to load province shape file: ", file_path); - province_shape_image.unref(); return err; } - width = province_shape_image->get_width(); - height = province_shape_image->get_height(); + int32_t width = province_shape_image->get_width(); + int32_t height = province_shape_image->get_height(); if (width < 1 || height < 1) { UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); err = FAILED; } static const Image::Format expected_format = Image::FORMAT_RGB8; - Image::Format format = province_shape_image->get_format(); + const Image::Format format = province_shape_image->get_format(); if (format != expected_format) { UtilityFunctions::push_error("Invalid format (", format, ", should be ", expected_format, ") for province shape file: ", file_path); err = FAILED; } - if (err) { - province_shape_image.unref(); - return err; - } + if (err != OK) return err; - std::vector province_checklist(map.get_province_count()); - - PackedByteArray shape_data_array = province_shape_image->get_data(), index_data_array; - index_data_array.resize(width * height * sizeof(Province::index_t)); - Province::index_t* index_data = reinterpret_cast(index_data_array.ptrw()); - - for (int32_t y = 0; y < height; ++y) { - for (int32_t x = 0; x < width; ++x) { - const int32_t idx = x + y * width; - const Province::colour_t colour = colour_at(shape_data_array, idx); - if (colour == Province::NULL_COLOUR) { - index_data[idx] = Province::NULL_INDEX; - continue; - } - if (x > 0) { - const int32_t jdx = idx - 1; - if (colour_at(shape_data_array, jdx) == colour) { - index_data[idx] = index_data[jdx]; - continue; - } - } - if (y > 0) { - const int32_t jdx = idx - width; - if (colour_at(shape_data_array, jdx) == colour) { - index_data[idx] = index_data[jdx]; - continue; - } - } - const Province* province = map.get_province_by_colour(colour); - if (province) { - Province::index_t index = province->get_index(); - index_data[idx] = index; - province_checklist[index - 1] = true; - continue; - } - UtilityFunctions::push_error("Unrecognised province colour ", Province::colour_to_hex_string(colour).c_str(), " at (", x, ", ", y, ")"); - err = FAILED; - index_data[idx] = Province::NULL_INDEX; - } + std::string error_message = ""; + if (map.generate_province_index_image(width, height, province_shape_image->get_data().ptr(), error_message) != SUCCESS) { + UtilityFunctions::push_error(error_message.c_str()); + err = FAILED; } - for (size_t idx = 0; idx < province_checklist.size(); ++idx) { - if (!province_checklist[idx]) { - Province* province = map.get_province_by_index(idx + 1); - if (province) UtilityFunctions::push_error("Province missing from shape image: ", province->to_string().c_str()); - else UtilityFunctions::push_error("Province missing for index: ", static_cast(idx + 1)); - err = FAILED; - } - } + PackedByteArray index_data_array; + index_data_array.resize(width * height * sizeof(Province::index_t)); + memcpy(index_data_array.ptrw(), map.get_province_index_image().data(), index_data_array.size()); province_index_image = Image::create_from_data(width, height, false, Image::FORMAT_RG8, index_data_array); if (province_index_image.is_null()) { @@ -206,45 +234,51 @@ Error MapSingleton::load_province_shape_file(String const& file_path) { err = FAILED; } - PackedByteArray colour_data_array; - colour_data_array.resize((Province::MAX_INDEX + 1) * 3); - for (size_t idx = 1; idx <= map.get_province_count(); ++idx) { - const Province* province = map.get_province_by_index(idx); - if (province) { - const Province::colour_t colour = province->get_colour(); - colour_data_array[3 * idx + 0] = (colour >> 16) & 0xFF; - colour_data_array[3 * idx + 1] = (colour >> 8) & 0xFF; - colour_data_array[3 * idx + 2] = colour & 0xFF; - } else UtilityFunctions::push_error("Missing province at index ", static_cast(idx)); - } - static const int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); - province_colour_image = Image::create_from_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, false, Image::FORMAT_RGB8, colour_data_array); - if (province_colour_image.is_null()) { - UtilityFunctions::push_error("Failed to create province colour image"); - err = FAILED; - } + if (update_colour_image() != OK) err = FAILED; return err; } -String MapSingleton::get_province_identifier_from_pixel_coords(Vector2i const& coords) { +Province* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) { + if (province_index_image.is_valid()) { + const PackedByteArray index_data_array = province_index_image->get_data(); + Province::index_t const* index_data = reinterpret_cast(index_data_array.ptr()); + const int32_t x_mod_w = UtilityFunctions::fposmod(coords.x, 1.0f) * get_width(); + const int32_t y_mod_h = UtilityFunctions::fposmod(coords.y, 1.0f) * get_height(); + return map.get_province_by_index(index_data[x_mod_w + y_mod_h * get_width()]); + } + return nullptr; +} + +Province const* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) const { if (province_index_image.is_valid()) { const PackedByteArray index_data_array = province_index_image->get_data(); - const Province::index_t* index_data = reinterpret_cast(index_data_array.ptr()); - const int32_t x_mod_w = UtilityFunctions::posmod(coords.x, width); - const int32_t y_mod_h = UtilityFunctions::posmod(coords.y, height); - const Province* province = map.get_province_by_index(index_data[x_mod_w + y_mod_h * width]); - if (province) return province->get_identifier().c_str(); + Province::index_t const* index_data = reinterpret_cast(index_data_array.ptr()); + const int32_t x_mod_w = UtilityFunctions::fposmod(coords.x, 1.0f) * get_width(); + const int32_t y_mod_h = UtilityFunctions::fposmod(coords.y, 1.0f) * get_height(); + return map.get_province_by_index(index_data[x_mod_w + y_mod_h * get_width()]); } + return nullptr; +} + +int32_t MapSingleton::get_province_index_from_uv_coords(Vector2 const& coords) const { + Province const* province = get_province_from_uv_coords(coords); + if (province != nullptr) return province->get_index(); + return Province::NULL_INDEX; +} + +String MapSingleton::get_province_identifier_from_uv_coords(Vector2 const& coords) const { + Province const* province = get_province_from_uv_coords(coords); + if (province != nullptr) return province->get_identifier().c_str(); return String{}; } int32_t MapSingleton::get_width() const { - return width; + return map.get_width(); } int32_t MapSingleton::get_height() const { - return height; + return map.get_height(); } Ref MapSingleton::get_province_index_image() const { @@ -254,3 +288,48 @@ Ref MapSingleton::get_province_index_image() const { Ref MapSingleton::get_province_colour_image() const { return province_colour_image; } + +Error MapSingleton::update_colour_image() { + static PackedByteArray colour_data_array; + static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 3; + colour_data_array.resize(colour_data_array_size); + + Error err = OK; + std::string error_message = ""; + if (map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw(), error_message) != SUCCESS) { + UtilityFunctions::push_error(error_message.c_str()); + err = FAILED; + } + + static const int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); + if (province_colour_image.is_null()) + province_colour_image.instantiate(); + province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, + false, Image::FORMAT_RGB8, colour_data_array); + if (province_colour_image.is_null()) { + UtilityFunctions::push_error("Failed to update province colour image"); + return FAILED; + } + return err; +} + +int32_t MapSingleton::get_mapmode_count() const { + return map.get_mapmode_count(); +} + +String MapSingleton::get_mapmode_identifier(int32_t index) const { + Mapmode const* mapmode = map.get_mapmode_by_index(index); + if (mapmode != nullptr) return mapmode->get_identifier().c_str(); + return String{}; +} + +Error MapSingleton::set_mapmode(godot::String const& identifier) { + Mapmode const* mapmode = map.get_mapmode_by_identifier(identifier.utf8().get_data()); + if (mapmode != nullptr) { + mapmode_index = mapmode->get_index(); + return OK; + } else { + UtilityFunctions::push_error("Failed to set mapmode to: ", identifier); + return FAILED; + } +} diff --git a/extension/src/MapSingleton.hpp b/extension/src/MapSingleton.hpp index 71761cd..9205e92 100644 --- a/extension/src/MapSingleton.hpp +++ b/extension/src/MapSingleton.hpp @@ -1,19 +1,27 @@ #pragma once +#include + #include + #include "openvic2/Map.hpp" namespace OpenVic2 { class MapSingleton : public godot::Object { + using parse_json_entry_func_t = std::function; GDCLASS(MapSingleton, godot::Object) static MapSingleton* singleton; - godot::Ref province_shape_image, province_index_image, province_colour_image; - int32_t width = 0, height = 0; + godot::Ref province_index_image, province_colour_image; Map map; + Mapmode::index_t mapmode_index = 0; + godot::Error parse_json_dictionary_file(godot::String const& file_description, godot::String const& file_path, + godot::String const& identifier_prefix, parse_json_entry_func_t parse_entry) const; + 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); protected: static void _bind_methods(); @@ -24,11 +32,21 @@ namespace OpenVic2 { ~MapSingleton(); godot::Error load_province_identifier_file(godot::String const& file_path); + godot::Error load_region_file(godot::String const& file_path); godot::Error load_province_shape_file(godot::String const& file_path); - godot::String get_province_identifier_from_pixel_coords(godot::Vector2i const& coords); + + Province* get_province_from_uv_coords(godot::Vector2 const& coords); + Province const* get_province_from_uv_coords(godot::Vector2 const& coords) const; + int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const; + godot::String get_province_identifier_from_uv_coords(godot::Vector2 const& coords) const; int32_t get_width() const; int32_t get_height() const; godot::Ref get_province_index_image() const; godot::Ref get_province_colour_image() const; + + godot::Error update_colour_image(); + int32_t get_mapmode_count() const; + godot::String get_mapmode_identifier(int32_t index) const; + godot::Error set_mapmode(godot::String const& identifier); }; } diff --git a/extension/src/Simulation.hpp b/extension/src/Simulation.hpp index 8959310..b84016b 100644 --- a/extension/src/Simulation.hpp +++ b/extension/src/Simulation.hpp @@ -1,8 +1,6 @@ #pragma once -#include #include -#include #include namespace OpenVic2 { @@ -11,7 +9,7 @@ namespace OpenVic2 { std::vector exampleProvinces; //BEGIN BOILERPLATE - static Simulation* _simulation; + inline static Simulation* _simulation = nullptr; protected: static void _bind_methods() { @@ -47,6 +45,4 @@ namespace OpenVic2 { return exampleProvinces[provinceID]; } }; - - Simulation* Simulation::_simulation = nullptr; } diff --git a/extension/src/TestSingleton.hpp b/extension/src/TestSingleton.hpp index d140516..1261573 100644 --- a/extension/src/TestSingleton.hpp +++ b/extension/src/TestSingleton.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include namespace OpenVic2 { class TestSingleton : public godot::Object diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp index d980b88..1654189 100644 --- a/extension/src/openvic2/Map.cpp +++ b/extension/src/openvic2/Map.cpp @@ -1,73 +1,126 @@ #include "Map.hpp" #include -#include -#include using namespace OpenVic2; -Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : - index(new_index), identifier(new_identifier), colour(new_colour) { - assert(index != NULL_INDEX); - assert(!identifier.empty()); - assert(colour != NULL_COLOUR); -} +static const std::string SEPARATOR = "\n - "; -std::string Province::colour_to_hex_string(colour_t colour) { - std::ostringstream stream; - stream << std::hex << std::setfill('0') << std::setw(6) << colour; - return stream.str(); +Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func) + : index(new_index), identifier(new_identifier), colour_func(new_colour_func) { + assert(!identifier.empty()); + assert(colour_func != nullptr); } -Province::index_t Province::get_index() const { +Mapmode::index_t Mapmode::get_index() const { return index; } -std::string const& Province::get_identifier() const { +std::string const& Mapmode::get_identifier() const { return identifier; } -Province::colour_t Province::get_colour() const { - return colour; -} - -std::string Province::to_string() const { - return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")"; +Mapmode::colour_func_t Mapmode::get_colour_func() const { + return colour_func; } -bool Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) { +return_t Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) { if (provinces_locked) { error_message = "The map's province list has already been locked!"; - return false; + return FAILURE; } if (provinces.size() >= Province::MAX_INDEX) { error_message = "The map's province list is full - there can be at most " + std::to_string(Province::MAX_INDEX) + " provinces"; - return false; + return FAILURE; + } + if (identifier.empty()) { + error_message = "Empty province identifier for colour " + Province::colour_to_hex_string(colour); + return FAILURE; } if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { error_message = "Invalid province colour: " + Province::colour_to_hex_string(colour); - return false; + return FAILURE; } Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; for (Province const& province : provinces) { - if (province.identifier == identifier) { + if (province.get_identifier() == identifier) { error_message = "Duplicate province identifiers: " + province.to_string() + " and " + new_province.to_string(); - return false; + return FAILURE; } - if (province.colour == colour) { + if (province.get_colour() == colour) { error_message = "Duplicate province colours: " + province.to_string() + " and " + new_province.to_string(); - return false; + return FAILURE; } } provinces.push_back(new_province); error_message = "Added province: " + new_province.to_string(); - return true; + return SUCCESS; } void Map::lock_provinces() { provinces_locked = true; } +return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message) { + if (regions_locked) { + error_message = "The map's region list has already been locked!"; + return FAILURE; + } + if (identifier.empty()) { + error_message = "Empty region identifier!"; + return FAILURE; + } + if (provinces.empty()) { + error_message = "Empty province list for region " + identifier; + return FAILURE; + } + Region new_region{ identifier }; + error_message = "Error message for region: " + identifier; + for (std::string const& province_identifier : province_identifiers) { + Province* province = get_province_by_identifier(province_identifier); + if (province != nullptr) { + if (new_region.contains_province(province)) + error_message += SEPARATOR + "Duplicate province identifier " + province_identifier; + else { + size_t other_region_index = reinterpret_cast(province->get_region()); + if (other_region_index != 0) { + other_region_index--; + error_message += SEPARATOR + "Province " + province_identifier + " is already part of "; + if (other_region_index < regions.size()) + error_message += regions[other_region_index].get_identifier(); + else + error_message += "an unknown region with index " + std::to_string(other_region_index); + } else new_region.provinces.push_back(province); + } + } else error_message += SEPARATOR + "Invalid province identifier " + province_identifier; + } + if (!new_region.get_province_count()) { + error_message += SEPARATOR + "No valid provinces in region's list"; + return FAILURE; + } + for (Region const& region : regions) { + if (region.get_identifier() == identifier) { + error_message += SEPARATOR + "Duplicate region identifiers: " + region.get_identifier() + " and " + identifier; + return FAILURE; + } + } + regions.push_back(new_region); + error_message += SEPARATOR + "Added region: " + identifier; + // Used to detect provinces listed in multiple regions, will + // be corrected once regions is stable (i.e. lock_regions). + Region* tmp_region_index = reinterpret_cast(regions.size()); + for (Province* province : new_region.get_provinces()) + province->region = tmp_region_index; + return SUCCESS; +} + +void Map::lock_regions() { + regions_locked = true; + for (Region& region : regions) + for (Province* province : region.get_provinces()) + province->region = ®ion; +} + size_t Map::get_province_count() const { return provinces.size(); } @@ -76,14 +129,178 @@ Province* Map::get_province_by_index(Province::index_t index) { return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; } +Province const* Map::get_province_by_index(Province::index_t index) const { + return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; +} + Province* Map::get_province_by_identifier(std::string const& identifier) { - for (Province& province : provinces) - if (province.identifier == identifier) return &province; + if (!identifier.empty()) + for (Province& province : provinces) + if (province.get_identifier() == identifier) return &province; + return nullptr; +} + +Province const* Map::get_province_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Province const& province : provinces) + if (province.get_identifier() == identifier) return &province; return nullptr; } Province* Map::get_province_by_colour(Province::colour_t colour) { - for (Province& province : provinces) - if (province.colour == colour) return &province; + if (colour != Province::NULL_COLOUR) + for (Province& province : provinces) + if (province.get_colour() == colour) return &province; + return nullptr; +} + +Province const* Map::get_province_by_colour(Province::colour_t colour) const { + if (colour != Province::NULL_COLOUR) + for (Province const& province : provinces) + if (province.get_colour() == colour) return &province; + return nullptr; +} + +static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) { + return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2]; +} + +return_t Map::generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message) { + if (!province_index_image.empty()) { + error_message = "Province index image has already been generated!"; + return FAILURE; + } + if (!provinces_locked) { + error_message = "Province index image cannot be generated until after provinces are locked!"; + return FAILURE; + } + if (new_width < 1 || new_height < 1) { + error_message = "Invalid province image dimensions: " + std::to_string(new_width) + "x" + std::to_string(new_height); + return FAILURE; + } + if (colour_data == nullptr) { + error_message = "Province colour data pointer is null!"; + return FAILURE; + } + width = new_width; + height = new_height; + province_index_image.resize(width * height); + + std::vector province_checklist(provinces.size()); + return_t ret = SUCCESS; + + error_message = "Error message for province index image generation:"; + + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + const int32_t idx = x + y * width; + const Province::colour_t colour = colour_at(colour_data, idx); + if (colour == Province::NULL_COLOUR) { + province_index_image[idx] = Province::NULL_INDEX; + continue; + } + if (x > 0) { + const int32_t jdx = idx - 1; + if (colour_at(colour_data, jdx) == colour) { + province_index_image[idx] = province_index_image[jdx]; + continue; + } + } + if (y > 0) { + const int32_t jdx = idx - width; + if (colour_at(colour_data, jdx) == colour) { + province_index_image[idx] = province_index_image[jdx]; + continue; + } + } + Province const* province = get_province_by_colour(colour); + if (province != nullptr) { + const Province::index_t index = province->get_index(); + province_index_image[idx] = index; + province_checklist[index - 1] = true; + continue; + } + error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(x) + ")"; + ret = FAILURE; + province_index_image[idx] = Province::NULL_INDEX; + } + } + + for (size_t idx = 0; idx < province_checklist.size(); ++idx) { + if (!province_checklist[idx]) { + error_message += SEPARATOR + "Province missing from shape image: " + provinces[idx].to_string(); + ret = FAILURE; + } + } + + error_message += SEPARATOR + "Generated province index image"; + return ret; +} + +size_t Map::get_width() const { + return width; +} + +size_t Map::get_height() const { + return height; +} + +std::vector const& Map::get_province_index_image() const { + return province_index_image; +} + +return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message) { + if (identifier.empty()) { + error_message = "Empty mapmode identifier!"; + return FAILURE; + } + if (colour_func == nullptr) { + error_message = "Mapmode colour function is null for identifier: " + identifier; + return FAILURE; + } + Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func }; + for (Mapmode const& mapmode : mapmodes) { + if (mapmode.get_identifier() == identifier) { + error_message = "Duplicate mapmode identifiers: " + mapmode.get_identifier() + " and " + identifier; + return FAILURE; + } + } + mapmodes.push_back(new_mapmode); + error_message = "Added mapmode: " + identifier; + return SUCCESS; +} + +size_t Map::get_mapmode_count() const { + return mapmodes.size(); +} + +Mapmode const* Map::get_mapmode_by_index(size_t index) const { + return index < mapmodes.size() ? &mapmodes[index] : nullptr; +} + +Mapmode const* Map::get_mapmode_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Mapmode const& mapmode : mapmodes) + if (mapmode.get_identifier() == identifier) return &mapmode; return nullptr; } + +return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const { + if (target == nullptr) { + error_message = "Mapmode colour target pointer is null!"; + return FAILURE; + } + if (index >= mapmodes.size()) { + error_message = "Invalid mapmode index: " + std::to_string(index); + return FAILURE; + } + Mapmode const& mapmode = mapmodes[index]; + target += 3; // Skip past Province::NULL_INDEX + for (Province const& province : provinces) { + const Province::colour_t colour = mapmode.get_colour_func()(*this, province); + *target++ = (colour >> 16) & 0xFF; + *target++ = (colour >> 8) & 0xFF; + *target++ = colour & 0xFF; + } + return SUCCESS; +} diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp index 365d78b..42963c9 100644 --- a/extension/src/openvic2/Map.hpp +++ b/extension/src/openvic2/Map.hpp @@ -3,43 +3,111 @@ #include #include #include +#include + +#include "Types.hpp" namespace OpenVic2 { + struct Region; + struct Map; + /* REQUIREMENTS: + * MAP-43, MAP-47 + */ struct Province { + friend struct Map; + using colour_t = uint32_t; using index_t = uint16_t; - friend struct Map; + static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; private: index_t index; std::string identifier; colour_t colour; + Region* region = nullptr; - Province(index_t index, std::string const& identifier, colour_t colour); + Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); public: static std::string colour_to_hex_string(colour_t colour); index_t get_index() const; std::string const& get_identifier() const; colour_t get_colour() const; + Region* get_region() const; std::string to_string() const; }; + /* REQUIREMENTS: + * MAP-6, MAP-44, MAP-48 + */ + struct Region { + friend struct Map; + private: + std::string identifier; + std::vector provinces; + + Region(std::string const& new_identifier); + public: + std::string const& get_identifier() const; + size_t get_province_count() const; + bool contains_province(Province const* province) const; + std::vector const& get_provinces() const; + }; + + struct Mapmode { + friend struct Map; + + using colour_func_t = std::function; + using index_t = size_t; + private: + index_t index; + std::string identifier; + colour_func_t colour_func; + + Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); + public: + index_t get_index() const; + std::string const& get_identifier() const; + colour_func_t get_colour_func() const; + }; + + /* REQUIREMENTS: + * MAP-4 + */ struct Map { private: std::vector provinces; - bool provinces_locked = false; + std::vector regions; + bool provinces_locked = false, regions_locked = false; + size_t width = 0, height = 0; + std::vector province_index_image; + std::vector mapmodes; public: - bool add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message); + return_t add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message); void lock_provinces(); + return_t add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message); + void lock_regions(); size_t get_province_count() const; Province* get_province_by_index(Province::index_t index); + Province const* get_province_by_index(Province::index_t index) const; Province* get_province_by_identifier(std::string const& identifier); + Province const* get_province_by_identifier(std::string const& identifier) const; Province* get_province_by_colour(Province::colour_t colour); - }; + Province const* get_province_by_colour(Province::colour_t colour) const; + + return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message); + size_t get_width() const; + size_t get_height() const; + std::vector const& get_province_index_image() const; + return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message); + size_t get_mapmode_count() const; + Mapmode const* get_mapmode_by_index(Mapmode::index_t index) const; + Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; + return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const; + }; } diff --git a/extension/src/openvic2/Province.cpp b/extension/src/openvic2/Province.cpp new file mode 100644 index 0000000..49f1b0e --- /dev/null +++ b/extension/src/openvic2/Province.cpp @@ -0,0 +1,40 @@ +#include "Map.hpp" + +#include +#include +#include + +using namespace OpenVic2; + +Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : + index(new_index), identifier(new_identifier), colour(new_colour) { + assert(index != NULL_INDEX); + assert(!identifier.empty()); + assert(colour != NULL_COLOUR); +} + +std::string Province::colour_to_hex_string(colour_t colour) { + std::ostringstream stream; + stream << std::hex << std::setfill('0') << std::setw(6) << colour; + return stream.str(); +} + +Province::index_t Province::get_index() const { + return index; +} + +std::string const& Province::get_identifier() const { + return identifier; +} + +Province::colour_t Province::get_colour() const { + return colour; +} + +Region* Province::get_region() const { + return region; +} + +std::string Province::to_string() const { + return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")"; +} diff --git a/extension/src/openvic2/Region.cpp b/extension/src/openvic2/Region.cpp new file mode 100644 index 0000000..6ee05f5 --- /dev/null +++ b/extension/src/openvic2/Region.cpp @@ -0,0 +1,26 @@ +#include "Map.hpp" + +#include +#include + +using namespace OpenVic2; + +Region::Region(std::string const& new_identifier) : identifier(new_identifier) { + assert(!identifier.empty()); +} + +std::string const& Region::get_identifier() const { + return identifier; +} + +size_t Region::get_province_count() const { + return provinces.size(); +} + +bool Region::contains_province(Province const* province) const { + return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); +} + +std::vector const& Region::get_provinces() const { + return provinces; +} diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp new file mode 100644 index 0000000..0fb1c8b --- /dev/null +++ b/extension/src/openvic2/Types.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace OpenVic2 { + using return_t = bool; + // This mirrors godot::Error, where `OK = 0` and `FAILED = 1`. + static const return_t SUCCESS = false, FAILURE = true; +} diff --git a/extension/src/register_types.cpp b/extension/src/register_types.cpp index 16e59b2..9fd934e 100644 --- a/extension/src/register_types.cpp +++ b/extension/src/register_types.cpp @@ -1,8 +1,5 @@ #include "register_types.h" -#include -#include -#include -#include + #include #include "TestSingleton.hpp" @@ -74,7 +71,7 @@ extern "C" { // Initialization. - GDExtensionBool GDE_EXPORT openvic2_library_init(const GDExtensionInterface* p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization* r_initialization) { + GDExtensionBool GDE_EXPORT openvic2_library_init(GDExtensionInterface const* p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization* r_initialization) { GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); init_obj.register_initializer(initialize_openvic2_types); diff --git a/extension/src/register_types.h b/extension/src/register_types.h index 860359f..1bc96f8 100644 --- a/extension/src/register_types.h +++ b/extension/src/register_types.h @@ -1,6 +1,6 @@ #pragma once -#include +#include void initialize_openvic2_types(godot::ModuleInitializationLevel); void uninitialize_openvic2_types(godot::ModuleInitializationLevel); \ No newline at end of file diff --git a/game/art/terrain/terrain.png b/game/art/terrain/terrain.png new file mode 100644 index 0000000..6d36dee Binary files /dev/null and b/game/art/terrain/terrain.png differ diff --git a/game/art/terrain/terrain.png.import b/game/art/terrain/terrain.png.import new file mode 100644 index 0000000..d7a078f --- /dev/null +++ b/game/art/terrain/terrain.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cmw0pvjthnn8c" +path="res://.godot/imported/terrain.png-06c63c2b87b3131a2067f668f87a9d67.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/terrain/terrain.png" +dest_files=["res://.godot/imported/terrain.png-06c63c2b87b3131a2067f668f87a9d67.ctex"] + +[params] + +compress/mode=3 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=false +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/art/ui/minimap.png b/game/art/ui/minimap.png new file mode 100644 index 0000000..9922b28 Binary files /dev/null and b/game/art/ui/minimap.png differ diff --git a/game/art/ui/minimap.png.import b/game/art/ui/minimap.png.import new file mode 100644 index 0000000..36f22e7 --- /dev/null +++ b/game/art/ui/minimap.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c0sm1jfu4kyv3" +path="res://.godot/imported/minimap.png-05ee44469856e77fd05107fe9e259e25.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/ui/minimap.png" +dest_files=["res://.godot/imported/minimap.png-05ee44469856e77fd05107fe9e259e25.ctex"] + +[params] + +compress/mode=3 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=false +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/art/ui/minimap_frame.png b/game/art/ui/minimap_frame.png new file mode 100644 index 0000000..21aa2ce Binary files /dev/null and b/game/art/ui/minimap_frame.png differ diff --git a/game/art/ui/minimap_frame.png.import b/game/art/ui/minimap_frame.png.import new file mode 100644 index 0000000..3d2aeee --- /dev/null +++ b/game/art/ui/minimap_frame.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vr1hq2stk8ny" +path="res://.godot/imported/minimap_frame.png-3668393435d2582fb1dc8a9598573e80.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/ui/minimap_frame.png" +dest_files=["res://.godot/imported/minimap_frame.png-3668393435d2582fb1dc8a9598573e80.ctex"] + +[params] + +compress/mode=3 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=false +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/common/map/regions.json b/game/common/map/regions.json new file mode 100644 index 0000000..bbeeb56 --- /dev/null +++ b/game/common/map/regions.json @@ -0,0 +1,6 @@ +{ + "region_europe": ["prov_britain", "prov_ireland", "prov_iceland"], + "region_america": ["prov_cuba"], + "region_africa": ["prov_madagascar"], + "region_asia": ["prov_ceylon", "prov_formosa"] +} diff --git a/game/common/map/terrain/terrain.png b/game/common/map/terrain/terrain.png deleted file mode 100644 index 6d36dee..0000000 Binary files a/game/common/map/terrain/terrain.png and /dev/null differ diff --git a/game/common/map/terrain/terrain.png.import b/game/common/map/terrain/terrain.png.import deleted file mode 100644 index 56ba5dc..0000000 --- a/game/common/map/terrain/terrain.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmw0pvjthnn8c" -path="res://.godot/imported/terrain.png-c443b8a709ca7acc4b3bb3df1d3095a9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://common/map/terrain/terrain.png" -dest_files=["res://.godot/imported/terrain.png-c443b8a709ca7acc4b3bb3df1d3095a9.ctex"] - -[params] - -compress/mode=3 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=2 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/game/localisation/en_GB/mapmodes.csv b/game/localisation/en_GB/mapmodes.csv new file mode 100644 index 0000000..c5b1bb0 --- /dev/null +++ b/game/localisation/en_GB/mapmodes.csv @@ -0,0 +1,5 @@ + +,, Test Mapmodes +mapmode_province,Province Mapmode +mapmode_region,Region Mapmode +mapmode_index,Index Mapmode diff --git a/game/localisation/en_GB/mapmodes.csv.import b/game/localisation/en_GB/mapmodes.csv.import new file mode 100644 index 0000000..8dd0c09 --- /dev/null +++ b/game/localisation/en_GB/mapmodes.csv.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index 040cb06..f4aac70 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -4,10 +4,15 @@ var Options = preload("Events/Options.gd").new() var Localisation = preload("Events/Localisation.gd").new() const _province_identifier_file : String = "res://common/map/provinces.json" +const _region_file : String = "res://common/map/regions.json" const _province_shape_file : String = "res://common/map/provinces.png" +# REQUIREMENTS +# * FS-333, FS-335, FS-341 func _ready(): if MapSingleton.load_province_identifier_file(_province_identifier_file) != OK: push_error("Failed to load province identifiers") + if MapSingleton.load_region_file(_region_file) != OK: + push_error("Failed to load regions") if MapSingleton.load_province_shape_file(_province_shape_file) != OK: push_error("Failed to load province shapes") diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index 390040e..e270f8a 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -7,7 +7,7 @@ [ext_resource type="PackedScene" uid="uid://byq323jbel48u" path="res://src/GameSession/ProvinceOverviewPanel.tscn" id="5_osjnn"] [node name="GameSession" type="Node" node_paths=PackedStringArray("_game_session_menu")] -editor_description = "SS-102" +editor_description = "SS-102, UI-546" script = ExtResource("1_eklvp") _game_session_menu = NodePath("GameSessionMenu") @@ -29,6 +29,8 @@ anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 +offset_left = -350.0 +offset_top = -210.0 grow_horizontal = 0 grow_vertical = 0 @@ -39,6 +41,11 @@ anchor_right = 0.15625 offset_top = 0.0 offset_right = 0.0 +[connection signal="map_view_camera_changed" from="MapView" to="MapControlPanel" method="_on_map_view_camera_changed"] [connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] [connection signal="close_button_pressed" from="GameSessionMenu" to="." method="_on_game_session_menu_close_button_pressed"] [connection signal="game_session_menu_button_pressed" from="MapControlPanel" to="." method="_on_game_session_menu_button_pressed"] +[connection signal="mapmode_changed" from="MapControlPanel" to="MapView" method="_update_colour_texture"] +[connection signal="minimap_clicked" from="MapControlPanel" to="MapView" method="_on_minimap_clicked"] +[connection signal="mouse_entered" from="MapControlPanel" to="MapView" method="_on_mouse_exited_viewport"] +[connection signal="mouse_exited" from="MapControlPanel" to="MapView" method="_on_mouse_entered_viewport"] diff --git a/game/src/GameSession/MapControlPanel.gd b/game/src/GameSession/MapControlPanel.gd index ad56536..693890f 100644 --- a/game/src/GameSession/MapControlPanel.gd +++ b/game/src/GameSession/MapControlPanel.gd @@ -1,8 +1,46 @@ extends PanelContainer signal game_session_menu_button_pressed +signal mapmode_changed +signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) +signal minimap_clicked(pos_clicked : Vector2) + +@export var _mapmodes_grid : GridContainer + +var _mapmode_button_group : ButtonGroup + +# REQUIREMENTS: +# * UI-550, UI-554 +func _add_mapmode_button(identifier : String) -> void: + var button := Button.new() + button.text = identifier + button.tooltip_text = identifier + button.toggle_mode = true + button.button_group = _mapmode_button_group + _mapmodes_grid.add_child(button) + if _mapmode_button_group.get_pressed_button() == null: + button.button_pressed = true + +func _ready(): + _mapmode_button_group = ButtonGroup.new() + _mapmode_button_group.pressed.connect(_mapmode_pressed) + for index in MapSingleton.get_mapmode_count(): + _add_mapmode_button(MapSingleton.get_mapmode_identifier(index)) # REQUIREMENTS: # * UIFUN-10 -func _on_game_session_menu_button_pressed(): +func _on_game_session_menu_button_pressed() -> void: game_session_menu_button_pressed.emit() + +# REQUIREMENTS: +# * SS-76 +# * UIFUN-129, UIFUN-133 +func _mapmode_pressed(button : BaseButton) -> void: + MapSingleton.set_mapmode(button.tooltip_text) + mapmode_changed.emit() + +func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void: + map_view_camera_changed.emit(near_left, far_left, far_right, near_right) + +func _on_minimap_clicked(pos_clicked : Vector2) -> void: + minimap_clicked.emit(pos_clicked) diff --git a/game/src/GameSession/MapControlPanel.tscn b/game/src/GameSession/MapControlPanel.tscn index 2a0c971..70d7eab 100644 --- a/game/src/GameSession/MapControlPanel.tscn +++ b/game/src/GameSession/MapControlPanel.tscn @@ -1,6 +1,9 @@ -[gd_scene load_steps=4 format=3 uid="uid://g524p8lr574w"] +[gd_scene load_steps=7 format=3 uid="uid://g524p8lr574w"] [ext_resource type="Script" path="res://src/GameSession/MapControlPanel.gd" id="1_ign64"] +[ext_resource type="Texture2D" uid="uid://c0sm1jfu4kyv3" path="res://art/ui/minimap.png" id="2_r613r"] +[ext_resource type="Script" path="res://src/GameSession/Minimap.gd" id="3_s4dml"] +[ext_resource type="Texture2D" uid="uid://vr1hq2stk8ny" path="res://art/ui/minimap_frame.png" id="4_f1exl"] [sub_resource type="InputEventAction" id="InputEventAction_5nck3"] action = &"ui_cancel" @@ -8,23 +11,42 @@ action = &"ui_cancel" [sub_resource type="Shortcut" id="Shortcut_fc1tk"] events = [SubResource("InputEventAction_5nck3")] -[node name="PanelContainer" type="PanelContainer"] +[node name="MapControlPanel" type="PanelContainer" node_paths=PackedStringArray("_mapmodes_grid")] editor_description = "SS-103" +mouse_filter = 1 script = ExtResource("1_ign64") +_mapmodes_grid = NodePath("HBoxContainer/VBoxContainer/MapmodesGrid") [node name="HBoxContainer" type="HBoxContainer" parent="."] layout_mode = 2 +alignment = 2 [node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] layout_mode = 2 -[node name="MapmodesPlaceholder" type="Label" parent="HBoxContainer/VBoxContainer"] +[node name="MapmodesGrid" type="GridContainer" parent="HBoxContainer/VBoxContainer"] +editor_description = "UI-750" layout_mode = 2 -text = "MAPMODES" +columns = 11 -[node name="MinimapPlaceholder" type="Label" parent="HBoxContainer/VBoxContainer"] +[node name="Minimap" type="PanelContainer" parent="HBoxContainer/VBoxContainer"] +editor_description = "UI-549" layout_mode = 2 -text = "MINIMAP" +mouse_filter = 1 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer/VBoxContainer/Minimap"] +editor_description = "UI-751, FS-338" +layout_mode = 2 +texture = ExtResource("2_r613r") + +[node name="ViewportQuad" type="Control" parent="HBoxContainer/VBoxContainer/Minimap"] +layout_mode = 2 +mouse_filter = 2 +script = ExtResource("3_s4dml") + +[node name="Frame" type="NinePatchRect" parent="HBoxContainer/VBoxContainer/Minimap"] +layout_mode = 2 +texture = ExtResource("4_f1exl") [node name="AuxiliaryPanel" type="VBoxContainer" parent="HBoxContainer"] editor_description = "UI-761" @@ -36,4 +58,6 @@ layout_mode = 2 shortcut = SubResource("Shortcut_fc1tk") text = "ESC" +[connection signal="map_view_camera_changed" from="." to="HBoxContainer/VBoxContainer/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] +[connection signal="minimap_clicked" from="HBoxContainer/VBoxContainer/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] [connection signal="pressed" from="HBoxContainer/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index faf90e8..54d8df8 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -1,6 +1,7 @@ extends Node3D signal province_selected(identifier : String) +signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) const _action_north : StringName = &"map_north" const _action_east : StringName = &"map_east" @@ -13,17 +14,19 @@ const _action_click : StringName = &"map_click" const _shader_param_province_index : StringName = &"province_index_tex" const _shader_param_province_colour : StringName = &"province_colour_tex" -const _shader_param_hover_pos : StringName = &"hover_pos" -const _shader_param_selected_pos : StringName = &"selected_pos" +const _shader_param_hover_index : StringName = &"hover_index" +const _shader_param_selected_index : StringName = &"selected_index" @export var _camera : Camera3D @export var _cardinal_move_speed : float = 1.0 -@export var _edge_move_threshold: float = 0.15 +@export var _edge_move_threshold: float = 0.02 @export var _edge_move_speed: float = 2.5 var _drag_anchor : Vector2 var _drag_active : bool = false +var _mouse_over_viewport : bool = false + @export var _zoom_target_min : float = 0.2 @export var _zoom_target_max : float = 5.0 @export var _zoom_target_step : float = 0.1 @@ -38,38 +41,33 @@ var _map_mesh : MapMesh var _map_shader_material : ShaderMaterial var _map_image_size : Vector2 var _map_province_index_image : Image +var _map_province_colour_image : Image +var _map_province_colour_texture : ImageTexture var _map_mesh_corner : Vector2 var _map_mesh_dims : Vector2 var _mouse_pos_viewport : Vector2 = Vector2(0.5, 0.5) var _mouse_pos_map : Vector2 = Vector2(0.5, 0.5) +var _viewport_dims : Vector2 = Vector2(1, 1) +# ??? Strange Godot/GDExtension Bug ??? +# Upon first opening a clone of this repo with the Godot Editor, +# if MapSingleton.get_province_index_image is called before MapMesh +# is referenced in the script below, then the editor will crash due +# to a failed HashMap lookup. I'm not sure if this is a bug in the +# editor, GDExtension, my own extension, or a combination of them. +# This was an absolute pain to track down. --- hop311 func _ready(): if _camera == null: push_error("MapView's _camera variable hasn't been set!") return + _zoom_target = _camera.position.y if _map_mesh_instance == null: push_error("MapView's _map_mesh variable hasn't been set!") return - if not _map_mesh_instance.mesh is MapMesh: - push_error("Invalid map mesh class: ", _map_mesh_instance.mesh.get_class(), "(expected MapMesh)") - return - _map_mesh = _map_mesh_instance.mesh - - # Set map mesh size and get bounds - _map_image_size = Vector2(Vector2i(MapSingleton.get_width(), MapSingleton.get_height())) - _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y - var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform - _map_mesh_corner = Vector2( - min(map_mesh_aabb.position.x, map_mesh_aabb.end.x), - min(map_mesh_aabb.position.z, map_mesh_aabb.end.z) - ) - _map_mesh_dims = abs(Vector2( - map_mesh_aabb.position.x - map_mesh_aabb.end.x, - map_mesh_aabb.position.z - map_mesh_aabb.end.z - )) - var map_material = _map_mesh_instance.get_active_material(0) + # Shader Material + var map_material := _map_mesh_instance.get_active_material(0) if map_material == null: push_error("Map mesh is missing material!") return @@ -77,6 +75,7 @@ func _ready(): push_error("Invalid map mesh material class: ", map_material.get_class()) return _map_shader_material = map_material + # Province index texture _map_province_index_image = MapSingleton.get_province_index_image() if _map_province_index_image == null: @@ -84,22 +83,72 @@ func _ready(): return var province_index_texture := ImageTexture.create_from_image(_map_province_index_image) _map_shader_material.set_shader_parameter(_shader_param_province_index, province_index_texture) + # Province colour texture - var province_colour_image = MapSingleton.get_province_colour_image() - if province_colour_image == null: + _map_province_colour_image = MapSingleton.get_province_colour_image() + if _map_province_colour_image == null: push_error("Failed to get province colour image!") return - var province_colour_texture := ImageTexture.create_from_image(province_colour_image) - _map_shader_material.set_shader_parameter(_shader_param_province_colour, province_colour_texture) + _map_province_colour_texture = ImageTexture.create_from_image(_map_province_colour_image) + _map_shader_material.set_shader_parameter(_shader_param_province_colour, _map_province_colour_texture) + + if not _map_mesh_instance.mesh is MapMesh: + push_error("Invalid map mesh class: ", _map_mesh_instance.mesh.get_class(), "(expected MapMesh)") + return + _map_mesh = _map_mesh_instance.mesh + + # Set map mesh size and get bounds + _map_image_size = Vector2(Vector2i(MapSingleton.get_width(), MapSingleton.get_height())) + _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y + var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform + _map_mesh_corner = Vector2( + min(map_mesh_aabb.position.x, map_mesh_aabb.end.x), + min(map_mesh_aabb.position.z, map_mesh_aabb.end.z) + ) + _map_mesh_dims = abs(Vector2( + map_mesh_aabb.position.x - map_mesh_aabb.end.x, + map_mesh_aabb.position.z - map_mesh_aabb.end.z + )) + +func _notification(what : int): + match what: + NOTIFICATION_WM_MOUSE_ENTER: # Mouse inside window + _on_mouse_entered_viewport() + NOTIFICATION_WM_MOUSE_EXIT: # Mouse out of window + _on_mouse_exited_viewport() + +func _update_colour_texture() -> void: + MapSingleton.update_colour_image() + _map_province_colour_texture.update(_map_province_colour_image) + +func _world_to_map_coords(pos : Vector3) -> Vector2: + return (Vector2(pos.x, pos.z) - _map_mesh_corner) / _map_mesh_dims + +func _viewport_to_map_coords(pos_viewport : Vector2) -> Vector2: + var ray_origin := _camera.project_ray_origin(pos_viewport) + var ray_normal := _camera.project_ray_normal(pos_viewport) + # Plane with normal (0,1,0) facing upwards, at a distance 0 from the origin + var intersection = Plane(0, 1, 0, 0).intersects_ray(ray_origin, ray_normal) + if typeof(intersection) == TYPE_VECTOR3: + return _world_to_map_coords(intersection as Vector3) + else: + # Normals parallel to the xz-plane could cause null intersections, + # but the camera's orientation should prevent such normals + push_error("Invalid intersection: ", intersection) + return Vector2(0.5, 0.5) +# REQUIREMENTS +# * SS-31 func _unhandled_input(event : InputEvent): if event.is_action_pressed(_action_click): # Check if the mouse is outside of bounds if _map_mesh.is_valid_uv_coord(_mouse_pos_map): - _map_shader_material.set_shader_parameter(_shader_param_selected_pos, _mouse_pos_map) - var mouse_pixel_pos := Vector2i(_mouse_pos_map * _map_image_size) - var province_identifier := MapSingleton.get_province_identifier_from_pixel_coords(mouse_pixel_pos) + var selected_index := MapSingleton.get_province_index_from_uv_coords(_mouse_pos_map) + _map_shader_material.set_shader_parameter(_shader_param_selected_index, selected_index) + var province_identifier := MapSingleton.get_province_identifier_from_uv_coords(_mouse_pos_map) province_selected.emit(province_identifier) + else: + print("Clicked outside the map!") elif event.is_action_pressed(_action_drag): if _drag_active: push_warning("Drag being activated while already active!") @@ -116,6 +165,7 @@ func _unhandled_input(event : InputEvent): func _physics_process(delta : float): _mouse_pos_viewport = get_viewport().get_mouse_position() + _viewport_dims = Vector2(Resolution.get_current_resolution()) # Process movement _movement_process(delta) # Keep within map bounds @@ -124,9 +174,13 @@ func _physics_process(delta : float): _zoom_process(delta) # Orient based on height _update_orientation() + # Update viewport on minimap + _update_minimap_viewport() # Calculate where the mouse lies on the map _update_mouse_map_position() +# REQUIREMENTS +# * UIFUN-124 func _movement_process(delta : float) -> void: var direction : Vector2 if _drag_active: @@ -137,13 +191,18 @@ func _movement_process(delta : float) -> void: direction *= _camera.position.y * delta _camera.position += Vector3(direction.x, 0, direction.y) +# REQUIREMENTS +# * UIFUN-125 func _edge_scrolling_vector() -> Vector2: - var viewport_dims := Vector2(Resolution.get_current_resolution()) - var mouse_vector := _mouse_pos_viewport / viewport_dims - Vector2(0.5, 0.5); - if pow(mouse_vector.x, 4) + pow(mouse_vector.y, 4) < pow(0.5 - _edge_move_threshold, 4): + if not _mouse_over_viewport: + return Vector2() + var mouse_vector := _mouse_pos_viewport / _viewport_dims - Vector2(0.5, 0.5) + if abs(mouse_vector.x) < 0.5 - _edge_move_threshold and abs(mouse_vector.y) < 0.5 - _edge_move_threshold: mouse_vector *= 0 return mouse_vector * _edge_move_speed +# REQUIREMENTS +# * SS-75 func _cardinal_movement_vector() -> Vector2: var move := Vector2( float(Input.is_action_pressed(_action_east)) - float(Input.is_action_pressed(_action_west)), @@ -155,6 +214,9 @@ func _clamp_over_map() -> void: _camera.position.x = _map_mesh_corner.x + fposmod(_camera.position.x - _map_mesh_corner.x, _map_mesh_dims.x) _camera.position.z = clamp(_camera.position.z, _map_mesh_corner.y, _map_mesh_corner.y + _map_mesh_dims.y) +# REQUIREMENTS +# * SS-74 +# * UIFUN-123 func _zoom_process(delta : float) -> void: var height := _camera.position.y var zoom := _zoom_target - height @@ -169,17 +231,27 @@ func _update_orientation() -> void: var dir := Vector3(0, -1, -exp(-_camera.position.y * 2.0 + 0.5)) _camera.look_at(_camera.position + dir) +func _update_minimap_viewport() -> void: + var near_left := _viewport_to_map_coords(Vector2(0, _viewport_dims.y)) + var far_left := _viewport_to_map_coords(Vector2(0, 0)) + var far_right := _viewport_to_map_coords(Vector2(_viewport_dims.x, 0)) + var near_right := _viewport_to_map_coords(_viewport_dims) + map_view_camera_changed.emit(near_left, far_left, far_right, near_right) + func _update_mouse_map_position() -> void: - var ray_origin := _camera.project_ray_origin(_mouse_pos_viewport) - var ray_normal := _camera.project_ray_normal(_mouse_pos_viewport) - # Plane with normal (0,1,0) facing upwards, at a distance 0 from the origin - var intersection = Plane(0, 1, 0, 0).intersects_ray(ray_origin, ray_normal) - if typeof(intersection) == TYPE_VECTOR3: - var intersection_vec := intersection as Vector3 - # This loops both horizontally (good) and vertically (bad) - _mouse_pos_map = (Vector2(intersection_vec.x, intersection_vec.z) - _map_mesh_corner) / _map_mesh_dims - _map_shader_material.set_shader_parameter(_shader_param_hover_pos, _mouse_pos_map) - else: - # Normals parallel to the xz-plane could cause null intersections, - # but the camera's orientation should prevent such normals - push_error("Invalid intersection: ", intersection) + _mouse_pos_map = _viewport_to_map_coords(_mouse_pos_viewport) + var hover_index := MapSingleton.get_province_index_from_uv_coords(_mouse_pos_map) + if _mouse_over_viewport: + _map_shader_material.set_shader_parameter(_shader_param_hover_index, hover_index) + +func _on_mouse_entered_viewport(): + _mouse_over_viewport = true + +func _on_mouse_exited_viewport(): + _mouse_over_viewport = false + +func _on_minimap_clicked(pos_clicked : Vector2): + pos_clicked *= _map_mesh_dims + _camera.position.x = pos_clicked.x + _camera.position.z = pos_clicked.y + _clamp_over_map() \ No newline at end of file diff --git a/game/src/GameSession/MapView.tscn b/game/src/GameSession/MapView.tscn index 4650acb..93fc162 100644 --- a/game/src/GameSession/MapView.tscn +++ b/game/src/GameSession/MapView.tscn @@ -2,26 +2,28 @@ [ext_resource type="Script" path="res://src/GameSession/MapView.gd" id="1_exccw"] [ext_resource type="Shader" path="res://src/GameSession/TerrainMap.gdshader" id="1_upocn"] -[ext_resource type="Texture2D" uid="uid://cmw0pvjthnn8c" path="res://common/map/terrain/terrain.png" id="3_l8pnf"] +[ext_resource type="Texture2D" uid="uid://cmw0pvjthnn8c" path="res://art/terrain/terrain.png" id="3_l8pnf"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_tayeg"] render_priority = 0 shader = ExtResource("1_upocn") -shader_parameter/hover_pos = Vector2(0.5, 0.5) -shader_parameter/selected_pos = Vector2(0.5, 0.5) +shader_parameter/hover_index = null +shader_parameter/selected_index = null shader_parameter/terrain_tex = ExtResource("3_l8pnf") [sub_resource type="MapMesh" id="MapMesh_3gtsd"] [node name="MapView" type="Node3D" node_paths=PackedStringArray("_camera", "_map_mesh_instance")] +editor_description = "SS-73" script = ExtResource("1_exccw") _camera = NodePath("MapCamera") _map_mesh_instance = NodePath("MapMeshInstance") [node name="MapCamera" type="Camera3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 1, 1) +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0.25, 1.5, -2.75) [node name="MapMeshInstance" type="MeshInstance3D" parent="."] +editor_description = "FS-343" transform = Transform3D(10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0) material_override = SubResource("ShaderMaterial_tayeg") mesh = SubResource("MapMesh_3gtsd") diff --git a/game/src/GameSession/Minimap.gd b/game/src/GameSession/Minimap.gd new file mode 100644 index 0000000..25c7cac --- /dev/null +++ b/game/src/GameSession/Minimap.gd @@ -0,0 +1,89 @@ +extends Control + +signal minimap_clicked(pos_clicked : Vector2) + +const _action_click : StringName = &"map_click" + +var _viewport_points : PackedVector2Array + +# REQUIREMENTS +# * SS-80 +# * UI-752 +func _draw() -> void: + if _viewport_points.size() > 1: + draw_multiline(_viewport_points, Color.WHITE, -1) + +# REQUIREMENTS +# * SS-81 +# * UIFUN-127 +func _unhandled_input(event : InputEvent): + if event is InputEventMouse and Input.is_action_pressed(_action_click): + var pos_clicked := get_local_mouse_position() / size - Vector2(0.5, 0.5) + if abs(pos_clicked.x) < 0.5 and abs(pos_clicked.y) < 0.5: + minimap_clicked.emit(pos_clicked) + +# Returns the point on the line going through p and q with the specific x coord +func _intersect_x(p : Vector2, q : Vector2, x : float) -> Vector2: + if p.x == q.x: + return Vector2(x, 0.5 * (p.y + q.y)) + var t := (x - q.x) / (p.x - q.x) + return q + t * (p - q) + +# Returns the point on the line going through p and q with the specific y coord +func _intersect_y(p : Vector2, q : Vector2, y : float) -> Vector2: + if p.y == q.y: + return Vector2(0.5 * (p.x + q.x), y) + var t := (y - q.y) / (p.y - q.y) + return q + t * (p - q) + +const _one_x := Vector2(1, 0) + +func _add_line_looped_over_x(left : Vector2, right : Vector2) -> void: + if left.x < 0: + if right.x < 0: + _viewport_points.push_back(left + _one_x) + _viewport_points.push_back(right + _one_x) + else: + var mid_point := _intersect_x(left, right, 0) + _viewport_points.push_back(mid_point) + _viewport_points.push_back(right) + mid_point.x = 1 + _viewport_points.push_back(left + _one_x) + _viewport_points.push_back(mid_point) + elif right.x > 1: + if left.x > 1: + _viewport_points.push_back(left - _one_x) + _viewport_points.push_back(right - _one_x) + else: + var mid_point := _intersect_x(left, right, 1) + _viewport_points.push_back(left) + _viewport_points.push_back(mid_point) + mid_point.x = 0 + _viewport_points.push_back(mid_point) + _viewport_points.push_back(right - _one_x) + else: + _viewport_points.push_back(left) + _viewport_points.push_back(right) + +# This can break if the viewport is rotated too far! +func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void: + # Bound far y coords + if far_left.y < 0: + far_left = _intersect_y(near_left, far_left, 0) + if far_right.y < 0: + far_right = _intersect_y(near_right, far_right, 0) + # Bound near y coords + if near_left.y > 1: + near_left = _intersect_y(near_left, far_left, 1) + if near_right.y > 1: + near_right = _intersect_y(near_right, far_right, 1) + + _viewport_points.clear() + _add_line_looped_over_x(near_left, near_right) + _add_line_looped_over_x(far_left, far_right) + _add_line_looped_over_x(far_left, near_left) + _add_line_looped_over_x(near_right, far_right) + + for i in _viewport_points.size(): + _viewport_points[i] *= size + queue_redraw() diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn index e21b1c3..2df95fb 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.tscn +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -3,6 +3,7 @@ [ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] [node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label")] +editor_description = "UI-56" anchors_preset = 2 anchor_top = 1.0 anchor_bottom = 1.0 @@ -23,6 +24,7 @@ offset_right = -10.0 offset_bottom = -5.0 [node name="ProvinceName" type="Label" parent="VBoxContainer"] +editor_description = "UI-57" layout_mode = 2 text = "PROVINCE_NAME" vertical_alignment = 1 diff --git a/game/src/GameSession/TerrainMap.gdshader b/game/src/GameSession/TerrainMap.gdshader index a6774fd..7aca0f9 100644 --- a/game/src/GameSession/TerrainMap.gdshader +++ b/game/src/GameSession/TerrainMap.gdshader @@ -8,10 +8,10 @@ uniform sampler2D terrain_tex: source_color, repeat_enable, filter_linear; uniform sampler2D province_index_tex : repeat_enable, filter_nearest; // Province colour texture uniform sampler2D province_colour_tex: source_color, repeat_enable, filter_nearest; -// Position of the mouse over the map mesh in UV coords -uniform vec2 hover_pos; -// Position in UV coords of a pixel belonging to the currently selected province -uniform vec2 selected_pos; +// Index of the mouse over the map mesh +uniform uint hover_index; +// Index of the currently selected province +uniform uint selected_index; uvec2 vec2_to_uvec2(vec2 v) { return uvec2(v * 255.0); @@ -31,13 +31,10 @@ uint read_uint16(sampler2D tex, vec2 uv) { void fragment() { uvec2 prov_idx_split = read_uvec2(province_index_tex, UV); - uint prov_index = uvec2_to_uint(prov_idx_split); - uint hover_index = read_uint16(province_index_tex, hover_pos); - uint selected_index = read_uint16(province_index_tex, selected_pos); // Boost prov_colour's contribution if it matches hover_colour or selected_colour - float mix_val = float(prov_index == hover_index) * 0.3 + float(prov_index == selected_index) * 0.5; + float mix_val = 0.3 + float(prov_index == hover_index) * 0.3 + float(prov_index == selected_index) * 0.3; // Don't mix if the province index is 0 mix_val *= float(prov_index != 0u); -- cgit v1.2.3-56-ga3b1 From 48558fdfec509942515b0e2d92e3f1357b201400 Mon Sep 17 00:00:00 2001 From: markomitos Date: Wed, 1 Mar 2023 23:20:58 +0100 Subject: Add Date to extension For absolute simulation dates Add TimeSpan to extension For relative simulation time Add Simulation Speed Management to extension Add Visual Studio directory to .gitignore Co-authored-by: ClarkeCode Co-authored-by: Hop311 --- .gitignore | 3 ++ extension/src/Simulation.cpp | 64 ++++++++++++++++++++++++ extension/src/Simulation.hpp | 30 +++++++++-- extension/src/openvic2/Date.cpp | 108 ++++++++++++++++++++++++++++++++++++++++ extension/src/openvic2/Date.hpp | 83 ++++++++++++++++++++++++++++++ 5 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 extension/src/Simulation.cpp create mode 100644 extension/src/openvic2/Date.cpp create mode 100644 extension/src/openvic2/Date.hpp diff --git a/.gitignore b/.gitignore index 125f143..596bc88 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,9 @@ !.vscode/launch.json !.vscode/tasks.json +# Visual Studio +.vs/ + # Godot 4+ specific ignores .godot/ game/bin/openvic2/* diff --git a/extension/src/Simulation.cpp b/extension/src/Simulation.cpp new file mode 100644 index 0000000..5ea99c5 --- /dev/null +++ b/extension/src/Simulation.cpp @@ -0,0 +1,64 @@ +#include "Simulation.hpp" + +namespace OpenVic2 { + void Simulation::togglePauseState() { + this->isPaused = !isPaused; + } + + bool Simulation::getPauseState() { + return this->isPaused; + } + + void Simulation::increaseSimulationSpeed() { + switch (this->currentSpeed) { + case(Speed::Speed1): + this->currentSpeed = Speed::Speed2; + break; + case(Speed::Speed2): + this->currentSpeed = Speed::Speed3; + break; + case(Speed::Speed3): + this->currentSpeed = Speed::Speed4; + break; + case(Speed::Speed4): + this->currentSpeed = Speed::Speed5; + break; + } + } + + void Simulation::decreaseSimulationSpeed() { + switch (this->currentSpeed) { + case(Speed::Speed2): + this->currentSpeed = Speed::Speed1; + break; + case(Speed::Speed3): + this->currentSpeed = Speed::Speed2; + break; + case(Speed::Speed4): + this->currentSpeed = Speed::Speed3; + break; + case(Speed::Speed5): + this->currentSpeed = Speed::Speed4; + break; + } + } + + void Simulation::setSimulationSpeed(Speed speed) { + this->currentSpeed = speed; + } + + int Simulation::getSimulationSpeed() { + return static_cast(this->currentSpeed); + } + + void Simulation::conditionallyAdvanceSimulation() { + if (!(this->isPaused)) { + std::chrono::time_point previousTime = this->lastPolledTime; + std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration_cast(currentTime - previousTime).count() >= this->getSimulationSpeed()) { + this->lastPolledTime = currentTime; + this->inGameDate++; + } + } + } +} diff --git a/extension/src/Simulation.hpp b/extension/src/Simulation.hpp index b84016b..58ba7c7 100644 --- a/extension/src/Simulation.hpp +++ b/extension/src/Simulation.hpp @@ -2,28 +2,39 @@ #include #include +#include +#include "openvic2/Date.hpp" namespace OpenVic2 { class Simulation : public godot::Object { GDCLASS(Simulation, godot::Object) std::vector exampleProvinces; + enum class Speed { Speed1 = 4000, Speed2 = 3000, Speed3 = 2000, Speed4 = 1000, Speed5 = 100, Speed6 = 1 }; + + std::chrono::time_point lastPolledTime; + bool isPaused; + Speed currentSpeed; + Date inGameDate; + //BEGIN BOILERPLATE inline static Simulation* _simulation = nullptr; - protected: + protected: static void _bind_methods() { godot::ClassDB::bind_method(godot::D_METHOD("conductSimulationStep"), &Simulation::conductSimulationStep); godot::ClassDB::bind_method(godot::D_METHOD("queryProvinceSize"), &Simulation::queryProvinceSize); } - public: + public: inline static Simulation* get_singleton() { return _simulation; } - inline Simulation() { + inline Simulation() : inGameDate(1836, 1, 1) { ERR_FAIL_COND(_simulation != nullptr); _simulation = this; - + this->lastPolledTime = std::chrono::high_resolution_clock::now(); + this->isPaused = false; + this->currentSpeed = Speed::Speed1; exampleProvinces.resize(10, 1); } inline ~Simulation() { @@ -32,6 +43,13 @@ namespace OpenVic2 { } //END BOILERPLATE + void togglePauseState(); + bool getPauseState(); + void increaseSimulationSpeed(); + void decreaseSimulationSpeed(); + void setSimulationSpeed(Speed speed); + int getSimulationSpeed(); + inline void conductSimulationStep() { for (uint64_t x = 0; x < exampleProvinces.size(); x++) { exampleProvinces[x] += (x + 1); @@ -44,5 +62,7 @@ namespace OpenVic2 { } return exampleProvinces[provinceID]; } + + void conditionallyAdvanceSimulation(); }; -} +} \ No newline at end of file diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp new file mode 100644 index 0000000..3c5b8d8 --- /dev/null +++ b/extension/src/openvic2/Date.cpp @@ -0,0 +1,108 @@ +#include +#include "Date.hpp" + +namespace OpenVic2 { + bool Timespan::operator< (Timespan const& other) const { return days < other.days; } + bool Timespan::operator> (Timespan const& other) const { return days > other.days; } + bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; } + bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; } + bool Timespan::operator== (Timespan const& other) const { return days == other.days; } + bool Timespan::operator!= (Timespan const& other) const { return days != other.days; } + + Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); } + Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); } + Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); } + Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); } + + Timespan& Timespan::operator+= (Timespan const& other) { + days += other.days; + return *this; + } + Timespan& Timespan::operator-= (Timespan const& other) { + days -= other.days; + return *this; + } + + Timespan fromYearZero(year_t year, month_t month, date_t day) { + int64_t daysElapsed = year * DAYS_IN_YEAR; + size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection + for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) { + daysElapsed += DAYS_IN_MONTH[x]; + } + daysElapsed += daysSinceMonthStart; + return Timespan(daysElapsed); + } + + //This function is not set up to handle dates before Year 0 + YearMonthDayBundle toGregorianDate(Timespan const& timespan) { + year_t year = 0; + month_t month = 0; + date_t day = 0; + + if (timespan >= 0) { + year = timespan.days / DAYS_IN_YEAR; + int64_t remainingDays = timespan.days % DAYS_IN_YEAR; + + for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) { + remainingDays -= DAYS_IN_MONTH[x]; + month++; + } + + //Corrects month and day to be 1-indexed + month++; + day++; + } + return std::make_tuple(year, month, day); + } + + + Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); } + + Date::Date(year_t year, month_t month, date_t day) { + ts = fromYearZero(year, month, day); + updateDate(ts); + } + + void Date::updateDate(Timespan const& timespan) { + gregorianDate = toGregorianDate(timespan); + } + + size_t Date::getDay() const { return std::get<2>(gregorianDate); } + size_t Date::getMonth() const { return std::get<1>(gregorianDate); } + size_t Date::getYear() const { return std::get<0>(gregorianDate); } + + bool Date::operator< (Date const& other) const { return ts < other.ts; } + bool Date::operator> (Date const& other) const { return ts > other.ts; } + bool Date::operator<= (Date const& other) const { return ts <= other.ts; } + bool Date::operator>= (Date const& other) const { return ts >= other.ts; } + bool Date::operator== (Date const& other) const { return ts == other.ts; } + bool Date::operator!= (Date const& other) const { return ts != other.ts; } + + Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); } + Timespan Date::operator- (Date const& other) const { return ts - other.ts; } + + Date& Date::operator+= (Timespan const& timespan) { + ts += timespan; + updateDate(ts); + return *this; + } + Date& Date::operator-= (Timespan const& timespan) { + ts -= timespan; + updateDate(ts); + return *this; + } + Date Date::operator++ (int) { + Date oldCopy = *this; + (*this) += 1; + return oldCopy; + } + + Date::operator std::string() const { + std::stringstream ss; + ss << getYear() << '.' << getMonth() << '.' << getDay(); + return ss.str(); + } + std::ostream &operator<<(std::ostream &out, Date const& date) { + return out << static_cast(date); + } +} diff --git a/extension/src/openvic2/Date.hpp b/extension/src/openvic2/Date.hpp new file mode 100644 index 0000000..841b118 --- /dev/null +++ b/extension/src/openvic2/Date.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace OpenVic2 { + //A relative period between points in time, measured in days + struct Timespan { + int64_t days; + + Timespan() : days(0) {} + Timespan(int64_t const& value) : days(value) {} + + bool operator< (Timespan const& other) const; + bool operator> (Timespan const& other) const; + bool operator<= (Timespan const& other) const; + bool operator>= (Timespan const& other) const; + bool operator== (Timespan const& other) const; + bool operator!= (Timespan const& other) const; + + Timespan operator+ (Timespan const& other) const; + Timespan operator- (Timespan const& other) const; + Timespan operator* (int64_t const& factor) const; + Timespan operator/ (int64_t const& factor) const; + + Timespan& operator+= (Timespan const& other); + Timespan& operator-= (Timespan const& other); + }; + + static constexpr size_t MONTHS_IN_YEAR = 12; + static constexpr size_t DAYS_IN_YEAR = 365; + static constexpr size_t DAYS_IN_MONTH[MONTHS_IN_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + using date_t = uint8_t; + using month_t = uint8_t; + using year_t = uint16_t; + using YearMonthDayBundle = std::tuple; + + //Represents an in-game date + //Note: Current implementation does not account for leap-years, or dates before Year 0 + struct Date { + private: + YearMonthDayBundle gregorianDate; + //Number of days since Jan 1st, Year 0 + Timespan ts; + + public: + //The Timespan is considered to be the number of days since Jan 1st, Year 0 + Date(Timespan const& timespan); + + //Year month day specification + Date(year_t year = 1836, month_t month = 1, date_t day = 1); + + private: + void updateDate(Timespan const& timespan); + + public: + size_t getDay() const; + size_t getMonth() const; + size_t getYear() const; + + bool operator< (Date const& other) const; + bool operator> (Date const& other) const; + bool operator<= (Date const& other) const; + bool operator>= (Date const& other) const; + bool operator== (Date const& other) const; + bool operator!= (Date const& other) const; + + Date operator+ (Timespan timespan) const; + Timespan operator- (Date const& other) const; + + Date& operator+= (Timespan const& timespan); + Date& operator-= (Timespan const& timespan); + //Postfix increment + Date operator++ (int); + + explicit operator std::string() const; + friend std::ostream& operator<< (std::ostream& out, Date const& date); + }; +} -- cgit v1.2.3-56-ga3b1 From 04b213d4e20ca4e7ea66b059329771f6fd36c650 Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Fri, 14 Apr 2023 23:41:57 -0400 Subject: Removing TestSingleton Extracted game advancement behaviour to separate class --- extension/src/Simulation.cpp | 64 ------------------------ extension/src/Simulation.hpp | 68 ------------------------- extension/src/TestSingleton.cpp | 36 -------------- extension/src/TestSingleton.hpp | 23 --------- extension/src/openvic2/GameAdvancementHook.cpp | 69 ++++++++++++++++++++++++++ extension/src/openvic2/GameAdvancementHook.hpp | 40 +++++++++++++++ extension/src/register_types.cpp | 20 -------- game/src/MainMenu/MainMenu.gd | 2 - 8 files changed, 109 insertions(+), 213 deletions(-) delete mode 100644 extension/src/Simulation.cpp delete mode 100644 extension/src/Simulation.hpp delete mode 100644 extension/src/TestSingleton.cpp delete mode 100644 extension/src/TestSingleton.hpp create mode 100644 extension/src/openvic2/GameAdvancementHook.cpp create mode 100644 extension/src/openvic2/GameAdvancementHook.hpp diff --git a/extension/src/Simulation.cpp b/extension/src/Simulation.cpp deleted file mode 100644 index 5ea99c5..0000000 --- a/extension/src/Simulation.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "Simulation.hpp" - -namespace OpenVic2 { - void Simulation::togglePauseState() { - this->isPaused = !isPaused; - } - - bool Simulation::getPauseState() { - return this->isPaused; - } - - void Simulation::increaseSimulationSpeed() { - switch (this->currentSpeed) { - case(Speed::Speed1): - this->currentSpeed = Speed::Speed2; - break; - case(Speed::Speed2): - this->currentSpeed = Speed::Speed3; - break; - case(Speed::Speed3): - this->currentSpeed = Speed::Speed4; - break; - case(Speed::Speed4): - this->currentSpeed = Speed::Speed5; - break; - } - } - - void Simulation::decreaseSimulationSpeed() { - switch (this->currentSpeed) { - case(Speed::Speed2): - this->currentSpeed = Speed::Speed1; - break; - case(Speed::Speed3): - this->currentSpeed = Speed::Speed2; - break; - case(Speed::Speed4): - this->currentSpeed = Speed::Speed3; - break; - case(Speed::Speed5): - this->currentSpeed = Speed::Speed4; - break; - } - } - - void Simulation::setSimulationSpeed(Speed speed) { - this->currentSpeed = speed; - } - - int Simulation::getSimulationSpeed() { - return static_cast(this->currentSpeed); - } - - void Simulation::conditionallyAdvanceSimulation() { - if (!(this->isPaused)) { - std::chrono::time_point previousTime = this->lastPolledTime; - std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); - if (std::chrono::duration_cast(currentTime - previousTime).count() >= this->getSimulationSpeed()) { - this->lastPolledTime = currentTime; - this->inGameDate++; - } - } - } -} diff --git a/extension/src/Simulation.hpp b/extension/src/Simulation.hpp deleted file mode 100644 index 58ba7c7..0000000 --- a/extension/src/Simulation.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include "openvic2/Date.hpp" - -namespace OpenVic2 { - class Simulation : public godot::Object { - GDCLASS(Simulation, godot::Object) - std::vector exampleProvinces; - - enum class Speed { Speed1 = 4000, Speed2 = 3000, Speed3 = 2000, Speed4 = 1000, Speed5 = 100, Speed6 = 1 }; - - std::chrono::time_point lastPolledTime; - bool isPaused; - Speed currentSpeed; - Date inGameDate; - - //BEGIN BOILERPLATE - inline static Simulation* _simulation = nullptr; - - protected: - static void _bind_methods() { - godot::ClassDB::bind_method(godot::D_METHOD("conductSimulationStep"), &Simulation::conductSimulationStep); - godot::ClassDB::bind_method(godot::D_METHOD("queryProvinceSize"), &Simulation::queryProvinceSize); - } - - public: - inline static Simulation* get_singleton() { return _simulation; } - - inline Simulation() : inGameDate(1836, 1, 1) { - ERR_FAIL_COND(_simulation != nullptr); - _simulation = this; - this->lastPolledTime = std::chrono::high_resolution_clock::now(); - this->isPaused = false; - this->currentSpeed = Speed::Speed1; - exampleProvinces.resize(10, 1); - } - inline ~Simulation() { - ERR_FAIL_COND(_simulation != this); - _simulation = nullptr; - } - //END BOILERPLATE - - void togglePauseState(); - bool getPauseState(); - void increaseSimulationSpeed(); - void decreaseSimulationSpeed(); - void setSimulationSpeed(Speed speed); - int getSimulationSpeed(); - - inline void conductSimulationStep() { - for (uint64_t x = 0; x < exampleProvinces.size(); x++) { - exampleProvinces[x] += (x + 1); - } - } - - inline uint64_t queryProvinceSize(uint64_t provinceID) { - if (provinceID >= exampleProvinces.size()) { - return 0; - } - return exampleProvinces[provinceID]; - } - - void conditionallyAdvanceSimulation(); - }; -} \ No newline at end of file diff --git a/extension/src/TestSingleton.cpp b/extension/src/TestSingleton.cpp deleted file mode 100644 index d9e2b03..0000000 --- a/extension/src/TestSingleton.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "TestSingleton.hpp" - -#include -#include - -using namespace godot; -using namespace OpenVic2; - -TestSingleton* TestSingleton::singleton = nullptr; - -void TestSingleton::_bind_methods() -{ - ClassDB::bind_method(D_METHOD("hello_singleton"), &TestSingleton::hello_singleton); -} - -TestSingleton* TestSingleton::get_singleton() -{ - return singleton; -} - -TestSingleton::TestSingleton() -{ - ERR_FAIL_COND(singleton != nullptr); - singleton = this; -} - -TestSingleton::~TestSingleton() -{ - ERR_FAIL_COND(singleton != this); - singleton = nullptr; -} - -void TestSingleton::hello_singleton() -{ - UtilityFunctions::print("Hello GDExtension Singleton!"); -} \ No newline at end of file diff --git a/extension/src/TestSingleton.hpp b/extension/src/TestSingleton.hpp deleted file mode 100644 index 1261573..0000000 --- a/extension/src/TestSingleton.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace OpenVic2 { - class TestSingleton : public godot::Object - { - GDCLASS(TestSingleton, godot::Object) - - static TestSingleton* singleton; - - protected: - static void _bind_methods(); - - public: - static TestSingleton* get_singleton(); - - TestSingleton(); - ~TestSingleton(); - - void hello_singleton(); - }; -} \ No newline at end of file diff --git a/extension/src/openvic2/GameAdvancementHook.cpp b/extension/src/openvic2/GameAdvancementHook.cpp new file mode 100644 index 0000000..3db3224 --- /dev/null +++ b/extension/src/openvic2/GameAdvancementHook.cpp @@ -0,0 +1,69 @@ +#include "GameAdvancementHook.hpp" + +namespace OpenVic2 { + GameAdvancementHook::GameAdvancementHook(AdvancementFunction function, bool startPaused, GameSpeed startingSpeed) { + triggerFunction = function; + lastPolledTime = std::chrono::high_resolution_clock::now(); + isPaused = startPaused; + currentSpeed = startingSpeed; + } + + void GameAdvancementHook::increaseSimulationSpeed() { + switch (currentSpeed) { + case(GameSpeed::Speed1): + currentSpeed = GameSpeed::Speed2; + break; + case(GameSpeed::Speed2): + currentSpeed = GameSpeed::Speed3; + break; + case(GameSpeed::Speed3): + currentSpeed = GameSpeed::Speed4; + break; + case(GameSpeed::Speed4): + currentSpeed = GameSpeed::Speed5; + break; + } + } + + void GameAdvancementHook::decreaseSimulationSpeed() { + switch (currentSpeed) { + case(GameSpeed::Speed2): + currentSpeed = GameSpeed::Speed1; + break; + case(GameSpeed::Speed3): + currentSpeed = GameSpeed::Speed2; + break; + case(GameSpeed::Speed4): + currentSpeed = GameSpeed::Speed3; + break; + case(GameSpeed::Speed5): + currentSpeed = GameSpeed::Speed4; + break; + } + } + + GameAdvancementHook GameAdvancementHook::operator++(int) { + GameAdvancementHook oldCopy = *this; + increaseSimulationSpeed(); + return oldCopy; + }; + + GameAdvancementHook GameAdvancementHook::operator--(int) { + GameAdvancementHook oldCopy = *this; + decreaseSimulationSpeed(); + return oldCopy; + }; + + void GameAdvancementHook::conditionallyAdvanceGame() { + if (!isPaused) { + std::chrono::time_point previousTime = lastPolledTime; + std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration_cast(currentTime - previousTime).count() >= static_cast(currentSpeed)) { + lastPolledTime = currentTime; + if (triggerFunction) { + triggerFunction(); + } + } + } + } +} \ No newline at end of file diff --git a/extension/src/openvic2/GameAdvancementHook.hpp b/extension/src/openvic2/GameAdvancementHook.hpp new file mode 100644 index 0000000..72af4ac --- /dev/null +++ b/extension/src/openvic2/GameAdvancementHook.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace OpenVic2 { + //Value of different game speeds are the minimum number of miliseconds before the simulation advances + enum class GameSpeed { + Speed1 = 4000, + Speed2 = 3000, + Speed3 = 2000, + Speed4 = 1000, + Speed5 = 100, + Speed6 = 1 + }; + + //Conditionally advances game with provided behaviour + //Class governs game speed and pause state + class GameAdvancementHook { + public: + using AdvancementFunction = std::function; + + private: + std::chrono::time_point lastPolledTime; + //A function pointer that advances the simulation, intended to be a capturing lambda or something similar. May need to be reworked later + AdvancementFunction triggerFunction; + + public: + bool isPaused; + GameSpeed currentSpeed; + + GameAdvancementHook(AdvancementFunction function = nullptr, bool startPaused = false, GameSpeed startingSpeed = GameSpeed::Speed1); + + void increaseSimulationSpeed(); + void decreaseSimulationSpeed(); + GameAdvancementHook operator++(int); + GameAdvancementHook operator--(int); + void conditionallyAdvanceGame(); + }; +} \ No newline at end of file diff --git a/extension/src/register_types.cpp b/extension/src/register_types.cpp index 9fd934e..10ed781 100644 --- a/extension/src/register_types.cpp +++ b/extension/src/register_types.cpp @@ -2,8 +2,6 @@ #include -#include "TestSingleton.hpp" -#include "Simulation.hpp" #include "Checksum.hpp" #include "LoadLocalisation.hpp" #include "MapSingleton.hpp" @@ -12,8 +10,6 @@ using namespace godot; using namespace OpenVic2; -static TestSingleton* _test_singleton; -static Simulation* _simulation; static Checksum* _checksum; static LoadLocalisation* _load_localisation; static MapSingleton* _map_singleton; @@ -23,14 +19,6 @@ void initialize_openvic2_types(ModuleInitializationLevel p_level) { return; } - ClassDB::register_class(); - _test_singleton = memnew(TestSingleton); - Engine::get_singleton()->register_singleton("TestSingleton", TestSingleton::get_singleton()); - - ClassDB::register_class(); - _simulation = memnew(Simulation); - Engine::get_singleton()->register_singleton("Simulation", Simulation::get_singleton()); - ClassDB::register_class(); _checksum = memnew(Checksum); Engine::get_singleton()->register_singleton("Checksum", Checksum::get_singleton()); @@ -51,12 +39,6 @@ void uninitialize_openvic2_types(ModuleInitializationLevel p_level) { return; } - Engine::get_singleton()->unregister_singleton("TestSingleton"); - memdelete(_test_singleton); - - Engine::get_singleton()->unregister_singleton("Simulation"); - memdelete(_simulation); - Engine::get_singleton()->unregister_singleton("Checksum"); memdelete(_checksum); @@ -68,9 +50,7 @@ void uninitialize_openvic2_types(ModuleInitializationLevel p_level) { } extern "C" { - // Initialization. - GDExtensionBool GDE_EXPORT openvic2_library_init(GDExtensionInterface const* p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization* r_initialization) { GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization); diff --git a/game/src/MainMenu/MainMenu.gd b/game/src/MainMenu/MainMenu.gd index 4420786..9d0edc6 100644 --- a/game/src/MainMenu/MainMenu.gd +++ b/game/src/MainMenu/MainMenu.gd @@ -10,8 +10,6 @@ var _new_game_button : BaseButton # REQUIREMENTS: # * SS-3 func _ready(): - print("From GDScript") - TestSingleton.hello_singleton() _on_new_game_button_visibility_changed() # REQUIREMENTS: -- cgit v1.2.3-56-ga3b1 From 1fdd198f943a41468b03b2cdc62c24147f707239 Mon Sep 17 00:00:00 2001 From: Hop311 Date: Tue, 18 Apr 2023 18:49:37 +0100 Subject: Better province image + terrain + some buttons --- extension/src/MapSingleton.cpp | 117 ++++++++++--- extension/src/MapSingleton.hpp | 6 +- extension/src/openvic2/Date.cpp | 181 ++++++++++--------- extension/src/openvic2/Date.hpp | 3 + extension/src/openvic2/Map.cpp | 132 +++++++++----- extension/src/openvic2/Map.hpp | 64 +------ extension/src/openvic2/Province.cpp | 19 +- extension/src/openvic2/Province.hpp | 39 +++++ extension/src/openvic2/Region.cpp | 24 +-- extension/src/openvic2/Region.hpp | 29 +++ extension/src/openvic2/Types.cpp | 13 ++ extension/src/openvic2/Types.hpp | 11 ++ game/art/terrain/farmlands.png | Bin 0 -> 265377 bytes game/art/terrain/farmlands.png.import | 34 ++++ game/art/terrain/terrain.png | Bin 27542091 -> 0 bytes game/art/terrain/terrain.png.import | 34 ---- game/common/map/provinces.json | 216 ++++++++++++++++++++++- game/common/map/provinces.png | Bin 9464 -> 1083451 bytes game/common/map/regions.json | 15 +- game/common/map/water.json | 6 + game/localisation/en_GB/mapmodes.csv | 1 + game/localisation/en_GB/menus.csv | 14 +- game/localisation/en_GB/provinces.csv | 223 +++++++++++++++++++++++- game/localisation/en_GB/regions.csv | 8 + game/localisation/en_GB/regions.csv.import | 3 + game/localisation/en_US/menus.csv | 7 +- game/localisation/fr_FR/menus.csv | 7 +- game/src/Autoload/Events.gd | 5 +- game/src/GameSession/GameSession.gd | 9 +- game/src/GameSession/GameSession.tscn | 32 ++-- game/src/GameSession/GameSessionMenu.gd | 21 ++- game/src/GameSession/GameSessionMenu.tscn | 59 ++++++- game/src/GameSession/MapControlPanel.gd | 13 ++ game/src/GameSession/MapControlPanel.tscn | 68 ++++++-- game/src/GameSession/MapView.gd | 30 +++- game/src/GameSession/MapView.tscn | 6 +- game/src/GameSession/ProvinceOverviewPanel.gd | 27 ++- game/src/GameSession/ProvinceOverviewPanel.tscn | 13 +- game/src/GameSession/TerrainMap.gdshader | 50 ++++-- 39 files changed, 1175 insertions(+), 364 deletions(-) create mode 100644 extension/src/openvic2/Province.hpp create mode 100644 extension/src/openvic2/Region.hpp create mode 100644 extension/src/openvic2/Types.cpp create mode 100644 game/art/terrain/farmlands.png create mode 100644 game/art/terrain/farmlands.png.import delete mode 100644 game/art/terrain/terrain.png delete mode 100644 game/art/terrain/terrain.png.import create mode 100644 game/common/map/water.json create mode 100644 game/localisation/en_GB/regions.csv create mode 100644 game/localisation/en_GB/regions.csv.import diff --git a/extension/src/MapSingleton.cpp b/extension/src/MapSingleton.cpp index 73cf522..6f90dee 100644 --- a/extension/src/MapSingleton.cpp +++ b/extension/src/MapSingleton.cpp @@ -11,11 +11,13 @@ MapSingleton* MapSingleton::singleton = nullptr; void MapSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &MapSingleton::load_province_identifier_file); + ClassDB::bind_method(D_METHOD("load_water_province_file", "file_path"), &MapSingleton::load_water_province_file); ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &MapSingleton::load_region_file); ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &MapSingleton::load_province_shape_file); ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &MapSingleton::get_province_index_from_uv_coords); ClassDB::bind_method(D_METHOD("get_province_identifier_from_uv_coords", "coords"), &MapSingleton::get_province_identifier_from_uv_coords); + ClassDB::bind_method(D_METHOD("get_region_identifier_from_province_identifier", "identifier"), &MapSingleton::get_region_identifier_from_province_identifier); ClassDB::bind_method(D_METHOD("get_width"), &MapSingleton::get_width); ClassDB::bind_method(D_METHOD("get_height"), &MapSingleton::get_height); ClassDB::bind_method(D_METHOD("get_province_index_image"), &MapSingleton::get_province_index_image); @@ -43,16 +45,19 @@ MapSingleton::MapSingleton() { { "mapmode_province", [](Map const&, Province const& province) -> Province::colour_t { return province.get_colour(); } }, { "mapmode_region", [](Map const&, Province const& province) -> Province::colour_t { Region const* region = province.get_region(); - if (region != nullptr) return region->get_provinces().front()->get_colour(); + if (region != nullptr) return region->get_colour(); return province.get_colour(); } }, + { "mapmode_terrain", [](Map const&, Province const& province) -> Province::colour_t { + return province.is_water() ? 0x4287F5 : 0x0D7017; + } }, { "mapmode_index", [](Map const& map, Province const& province) -> Province::colour_t { const uint8_t f = float(province.get_index()) / float(map.get_province_count()) * 255.0f; return (f << 16) | (f << 8) | f; } } }; - std::string error_message = ""; - for (mapmode_t mapmode : mapmodes) + std::string error_message; + for (mapmode_t const& mapmode : mapmodes) if (map.add_mapmode(mapmode.first, mapmode.second, error_message) != SUCCESS) UtilityFunctions::push_error(error_message.c_str()); } @@ -62,34 +67,43 @@ MapSingleton::~MapSingleton() { singleton = nullptr; } -Error MapSingleton::parse_json_dictionary_file(String const& file_description, String const& file_path, - String const& identifier_prefix, parse_json_entry_func_t parse_entry) const { +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); - Ref file = FileAccess::open(file_path, FileAccess::ModeFlags::READ); + const Ref 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.instantiate(); - err = json->parse(json_string); + JSON json; + 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()); + "\nError at line ", json.get_error_line(), ": ", json.get_error_message()); return err; } - const Variant json_var = json->get_data(); + result = json.get_data(); + return err; +} + +using parse_json_entry_func_t = std::function; + +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; } - const Dictionary dict = json_var; + Dictionary const& dict = json_var; const Array identifiers = dict.keys(); - for (int idx = 0; idx < identifiers.size(); ++idx) { + for (int64_t idx = 0; idx < identifiers.size(); ++idx) { String const& identifier = identifiers[idx]; Variant const& entry = dict[identifier]; if (identifier.is_empty()) { @@ -108,20 +122,20 @@ Error MapSingleton::_parse_province_identifier_entry(String const& identifier, V const Variant::Type type = entry.get_type(); Province::colour_t colour = Province::NULL_COLOUR; if (type == Variant::ARRAY) { - const Array colour_array = entry; + Array const& colour_array = entry; if (colour_array.size() == 3) { for (int jdx = 0; jdx < 3; ++jdx) { - const Variant var = colour_array[jdx]; + Variant const& var = colour_array[jdx]; if (var.get_type() != Variant::FLOAT) { colour = Province::NULL_COLOUR; break; } - double colour_double = var; + const double colour_double = var; if (std::trunc(colour_double) != colour_double) { colour = Province::NULL_COLOUR; break; } - int64_t colour_int = static_cast(colour_double); + const int64_t colour_int = static_cast(colour_double); if (colour_int < 0 || colour_int > 255) { colour = Province::NULL_COLOUR; break; @@ -130,17 +144,18 @@ Error MapSingleton::_parse_province_identifier_entry(String const& identifier, V } } } else if (type == Variant::STRING) { - String colour_string = entry; + String const& colour_string = entry; if (colour_string.is_valid_hex_number()) { - int64_t colour_int = colour_string.hex_to_int(); + const int64_t colour_int = colour_string.hex_to_int(); if (0 <= colour_int && colour_int <= 0xFFFFFF) colour = colour_int; } - } else { + } + if (colour == Province::NULL_COLOUR) { UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry); return FAILED; } - std::string error_message = ""; + std::string error_message; if (map.add_province(identifier.utf8().get_data(), colour, error_message) != SUCCESS) { UtilityFunctions::push_error(error_message.c_str()); return FAILED; @@ -162,12 +177,12 @@ Error MapSingleton::_parse_region_entry(String const& identifier, Variant const& Variant::Type type = entry.get_type(); std::vector province_identifiers; if (type == Variant::ARRAY) { - const Array province_array = entry; + Array const& province_array = entry; for (int64_t idx = 0; idx < province_array.size(); ++idx) { - const Variant province_var = province_array[idx]; + Variant const& province_var = province_array[idx]; type = province_var.get_type(); if (type == Variant::STRING) { - String province_string = province_var; + String const& province_string = province_var; province_identifiers.push_back(province_string.utf8().get_data()); } else { UtilityFunctions::push_error("Invalid province identifier for region \"", identifier, "\": ", entry); @@ -175,7 +190,11 @@ Error MapSingleton::_parse_region_entry(String const& identifier, Variant const& } } } - std::string error_message = ""; + if (province_identifiers.empty()) { + UtilityFunctions::push_error("Invalid province list for region \"", identifier, "\": ", entry); + return FAILED; + } + std::string error_message; if (map.add_region(identifier.utf8().get_data(), province_identifiers, error_message) != SUCCESS) { UtilityFunctions::push_error(error_message.c_str()); return FAILED; @@ -218,7 +237,7 @@ Error MapSingleton::load_province_shape_file(String const& file_path) { } if (err != OK) return err; - std::string error_message = ""; + std::string error_message; if (map.generate_province_index_image(width, height, province_shape_image->get_data().ptr(), error_message) != SUCCESS) { UtilityFunctions::push_error(error_message.c_str()); err = FAILED; @@ -239,6 +258,37 @@ Error MapSingleton::load_province_shape_file(String const& file_path) { return err; } +Error MapSingleton::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; + std::string error_message; + 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 (map.set_water_province(identifier.utf8().get_data(), error_message) != SUCCESS) { + UtilityFunctions::push_error(error_message.c_str()); + err = FAILED; + } + } + } + map.lock_water_provinces(); + return err; +} + Province* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) { if (province_index_image.is_valid()) { const PackedByteArray index_data_array = province_index_image->get_data(); @@ -273,6 +323,15 @@ String MapSingleton::get_province_identifier_from_uv_coords(Vector2 const& coord return String{}; } +String MapSingleton::get_region_identifier_from_province_identifier(String const& identifier) const { + Province const* province = map.get_province_by_identifier(identifier.utf8().get_data()); + if (province != nullptr) { + Region const* region = province->get_region(); + if (region != nullptr) return region->get_identifier().c_str(); + } + return String{}; +} + int32_t MapSingleton::get_width() const { return map.get_width(); } @@ -291,11 +350,11 @@ Ref MapSingleton::get_province_colour_image() const { Error MapSingleton::update_colour_image() { static PackedByteArray colour_data_array; - static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 3; + static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 4; colour_data_array.resize(colour_data_array_size); Error err = OK; - std::string error_message = ""; + std::string error_message; if (map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw(), error_message) != SUCCESS) { UtilityFunctions::push_error(error_message.c_str()); err = FAILED; @@ -305,7 +364,7 @@ Error MapSingleton::update_colour_image() { if (province_colour_image.is_null()) province_colour_image.instantiate(); province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, - false, Image::FORMAT_RGB8, colour_data_array); + false, Image::FORMAT_RGBA8, colour_data_array); if (province_colour_image.is_null()) { UtilityFunctions::push_error("Failed to update province colour image"); return FAILED; diff --git a/extension/src/MapSingleton.hpp b/extension/src/MapSingleton.hpp index 9205e92..6ec2ea4 100644 --- a/extension/src/MapSingleton.hpp +++ b/extension/src/MapSingleton.hpp @@ -8,8 +8,6 @@ namespace OpenVic2 { class MapSingleton : public godot::Object { - using parse_json_entry_func_t = std::function; - GDCLASS(MapSingleton, godot::Object) static MapSingleton* singleton; @@ -18,8 +16,6 @@ namespace OpenVic2 { Map map; Mapmode::index_t mapmode_index = 0; - godot::Error parse_json_dictionary_file(godot::String const& file_description, godot::String const& file_path, - godot::String const& identifier_prefix, parse_json_entry_func_t parse_entry) const; 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); protected: @@ -32,6 +28,7 @@ namespace OpenVic2 { ~MapSingleton(); 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_province_shape_file(godot::String const& file_path); @@ -39,6 +36,7 @@ namespace OpenVic2 { Province const* get_province_from_uv_coords(godot::Vector2 const& coords) const; int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const; godot::String get_province_identifier_from_uv_coords(godot::Vector2 const& coords) const; + godot::String get_region_identifier_from_province_identifier(godot::String const& identifier) const; int32_t get_width() const; int32_t get_height() const; godot::Ref get_province_index_image() const; diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp index 3c5b8d8..e1cef72 100644 --- a/extension/src/openvic2/Date.cpp +++ b/extension/src/openvic2/Date.cpp @@ -1,108 +1,115 @@ #include #include "Date.hpp" -namespace OpenVic2 { - bool Timespan::operator< (Timespan const& other) const { return days < other.days; } - bool Timespan::operator> (Timespan const& other) const { return days > other.days; } - bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; } - bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; } - bool Timespan::operator== (Timespan const& other) const { return days == other.days; } - bool Timespan::operator!= (Timespan const& other) const { return days != other.days; } - - Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); } - Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); } - Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); } - Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); } - - Timespan& Timespan::operator+= (Timespan const& other) { - days += other.days; - return *this; - } - Timespan& Timespan::operator-= (Timespan const& other) { - days -= other.days; - return *this; - } +using namespace OpenVic2; + +bool Timespan::operator< (Timespan const& other) const { return days < other.days; } +bool Timespan::operator> (Timespan const& other) const { return days > other.days; } +bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; } +bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; } +bool Timespan::operator== (Timespan const& other) const { return days == other.days; } +bool Timespan::operator!= (Timespan const& other) const { return days != other.days; } + +Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); } +Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); } +Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); } +Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); } + +Timespan& Timespan::operator+= (Timespan const& other) { + days += other.days; + return *this; +} +Timespan& Timespan::operator-= (Timespan const& other) { + days -= other.days; + return *this; +} - Timespan fromYearZero(year_t year, month_t month, date_t day) { - int64_t daysElapsed = year * DAYS_IN_YEAR; - size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection - for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) { - daysElapsed += DAYS_IN_MONTH[x]; - } - daysElapsed += daysSinceMonthStart; - return Timespan(daysElapsed); - } +Timespan::operator std::string() const { + return std::to_string(days); +} +std::ostream &operator<<(std::ostream &out, Timespan const& timespan) { + return out << static_cast(timespan); +} - //This function is not set up to handle dates before Year 0 - YearMonthDayBundle toGregorianDate(Timespan const& timespan) { - year_t year = 0; - month_t month = 0; - date_t day = 0; +Timespan fromYearZero(year_t year, month_t month, date_t day) { + int64_t daysElapsed = year * DAYS_IN_YEAR; + size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection + for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) { + daysElapsed += DAYS_IN_MONTH[x]; + } + daysElapsed += daysSinceMonthStart; + return Timespan(daysElapsed); +} - if (timespan >= 0) { - year = timespan.days / DAYS_IN_YEAR; - int64_t remainingDays = timespan.days % DAYS_IN_YEAR; +//This function is not set up to handle dates before Year 0 +YearMonthDayBundle toGregorianDate(Timespan const& timespan) { + year_t year = 0; + month_t month = 0; + date_t day = 0; - for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) { - remainingDays -= DAYS_IN_MONTH[x]; - month++; - } + if (timespan >= 0) { + year = timespan.days / DAYS_IN_YEAR; + int64_t remainingDays = timespan.days % DAYS_IN_YEAR; - //Corrects month and day to be 1-indexed + for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) { + remainingDays -= DAYS_IN_MONTH[x]; month++; - day++; } - return std::make_tuple(year, month, day); + + //Corrects month and day to be 1-indexed + month++; + day++; } + return std::make_tuple(year, month, day); +} - Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); } +Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); } - Date::Date(year_t year, month_t month, date_t day) { - ts = fromYearZero(year, month, day); - updateDate(ts); - } +Date::Date(year_t year, month_t month, date_t day) { + ts = fromYearZero(year, month, day); + updateDate(ts); +} - void Date::updateDate(Timespan const& timespan) { - gregorianDate = toGregorianDate(timespan); - } +void Date::updateDate(Timespan const& timespan) { + gregorianDate = toGregorianDate(timespan); +} - size_t Date::getDay() const { return std::get<2>(gregorianDate); } - size_t Date::getMonth() const { return std::get<1>(gregorianDate); } - size_t Date::getYear() const { return std::get<0>(gregorianDate); } +size_t Date::getDay() const { return std::get<2>(gregorianDate); } +size_t Date::getMonth() const { return std::get<1>(gregorianDate); } +size_t Date::getYear() const { return std::get<0>(gregorianDate); } - bool Date::operator< (Date const& other) const { return ts < other.ts; } - bool Date::operator> (Date const& other) const { return ts > other.ts; } - bool Date::operator<= (Date const& other) const { return ts <= other.ts; } - bool Date::operator>= (Date const& other) const { return ts >= other.ts; } - bool Date::operator== (Date const& other) const { return ts == other.ts; } - bool Date::operator!= (Date const& other) const { return ts != other.ts; } +bool Date::operator< (Date const& other) const { return ts < other.ts; } +bool Date::operator> (Date const& other) const { return ts > other.ts; } +bool Date::operator<= (Date const& other) const { return ts <= other.ts; } +bool Date::operator>= (Date const& other) const { return ts >= other.ts; } +bool Date::operator== (Date const& other) const { return ts == other.ts; } +bool Date::operator!= (Date const& other) const { return ts != other.ts; } - Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); } - Timespan Date::operator- (Date const& other) const { return ts - other.ts; } +Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); } +Timespan Date::operator- (Date const& other) const { return ts - other.ts; } - Date& Date::operator+= (Timespan const& timespan) { - ts += timespan; - updateDate(ts); - return *this; - } - Date& Date::operator-= (Timespan const& timespan) { - ts -= timespan; - updateDate(ts); - return *this; - } - Date Date::operator++ (int) { - Date oldCopy = *this; - (*this) += 1; - return oldCopy; - } +Date& Date::operator+= (Timespan const& timespan) { + ts += timespan; + updateDate(ts); + return *this; +} +Date& Date::operator-= (Timespan const& timespan) { + ts -= timespan; + updateDate(ts); + return *this; +} +Date Date::operator++ (int) { + Date oldCopy = *this; + (*this) += 1; + return oldCopy; +} - Date::operator std::string() const { - std::stringstream ss; - ss << getYear() << '.' << getMonth() << '.' << getDay(); - return ss.str(); - } - std::ostream &operator<<(std::ostream &out, Date const& date) { - return out << static_cast(date); - } +Date::operator std::string() const { + std::stringstream ss; + ss << getYear() << '.' << getMonth() << '.' << getDay(); + return ss.str(); +} +std::ostream &operator<<(std::ostream &out, Date const& date) { + return out << static_cast(date); } diff --git a/extension/src/openvic2/Date.hpp b/extension/src/openvic2/Date.hpp index 841b118..9ed5963 100644 --- a/extension/src/openvic2/Date.hpp +++ b/extension/src/openvic2/Date.hpp @@ -28,6 +28,9 @@ namespace OpenVic2 { Timespan& operator+= (Timespan const& other); Timespan& operator-= (Timespan const& other); + + explicit operator std::string() const; + friend std::ostream& operator<< (std::ostream& out, Timespan const& timespan); }; static constexpr size_t MONTHS_IN_YEAR = 12; diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp index 1654189..0ac8091 100644 --- a/extension/src/openvic2/Map.cpp +++ b/extension/src/openvic2/Map.cpp @@ -1,14 +1,14 @@ #include "Map.hpp" #include +#include using namespace OpenVic2; static const std::string SEPARATOR = "\n - "; Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func) - : index(new_index), identifier(new_identifier), colour_func(new_colour_func) { - assert(!identifier.empty()); + : HasIdentifier(new_identifier), index(new_index), colour_func(new_colour_func) { assert(colour_func != nullptr); } @@ -16,10 +16,6 @@ Mapmode::index_t Mapmode::get_index() const { return index; } -std::string const& Mapmode::get_identifier() const { - return identifier; -} - Mapmode::colour_func_t Mapmode::get_colour_func() const { return colour_func; } @@ -42,15 +38,15 @@ return_t Map::add_province(std::string const& identifier, Province::colour_t col return FAILURE; } Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; - for (Province const& province : provinces) { - if (province.get_identifier() == identifier) { - error_message = "Duplicate province identifiers: " + province.to_string() + " and " + new_province.to_string(); - return FAILURE; - } - if (province.get_colour() == colour) { - error_message = "Duplicate province colours: " + province.to_string() + " and " + new_province.to_string(); - return FAILURE; - } + Province const* old_province = get_province_by_identifier(identifier); + if (old_province != nullptr) { + error_message = "Duplicate province identifiers: " + old_province->to_string() + " and " + new_province.to_string(); + return FAILURE; + } + old_province = get_province_by_colour(colour); + if (old_province != nullptr) { + error_message = "Duplicate province colours: " + old_province->to_string() + " and " + new_province.to_string(); + return FAILURE; } provinces.push_back(new_province); error_message = "Added province: " + new_province.to_string(); @@ -61,6 +57,29 @@ void Map::lock_provinces() { provinces_locked = true; } +return_t Map::set_water_province(std::string const& identifier, std::string& error_message) { + if (water_provinces_locked) { + error_message = "The map's water provinces have already been locked!"; + return FAILURE; + } + Province* province = get_province_by_identifier(identifier); + if (province == nullptr) { + error_message = "Unrecognised water province identifier: " + identifier; + return FAILURE; + } + if (province->is_water()) { + error_message = "Province " + identifier + " is already a water province!"; + return FAILURE; + } + province->water = true; + error_message = "Set province " + identifier + " as a water province"; + return SUCCESS; +} + +void Map::lock_water_provinces() { + water_provinces_locked = true; +} + return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message) { if (regions_locked) { error_message = "The map's region list has already been locked!"; @@ -75,7 +94,7 @@ return_t Map::add_region(std::string const& identifier, std::vector return FAILURE; } Region new_region{ identifier }; - error_message = "Error message for region: " + identifier; + error_message.clear(); for (std::string const& province_identifier : province_identifiers) { Province* province = get_province_by_identifier(province_identifier); if (province != nullptr) { @@ -90,28 +109,36 @@ return_t Map::add_region(std::string const& identifier, std::vector error_message += regions[other_region_index].get_identifier(); else error_message += "an unknown region with index " + std::to_string(other_region_index); - } else new_region.provinces.push_back(province); + } else new_region.provinces.insert(province); } } else error_message += SEPARATOR + "Invalid province identifier " + province_identifier; } + return_t ret = SUCCESS; if (!new_region.get_province_count()) { error_message += SEPARATOR + "No valid provinces in region's list"; - return FAILURE; + ret = FAILURE; } - for (Region const& region : regions) { - if (region.get_identifier() == identifier) { - error_message += SEPARATOR + "Duplicate region identifiers: " + region.get_identifier() + " and " + identifier; - return FAILURE; + Region const* old_region = get_region_by_identifier(identifier); + if (old_region != nullptr) { + error_message += SEPARATOR + "Duplicate region identifiers: " + old_region->get_identifier() + " and " + identifier; + ret = FAILURE; + } + + if (ret == SUCCESS) { + regions.push_back(new_region); + // Used to detect provinces listed in multiple regions, will + // be corrected once regions is stable (i.e. lock_regions). + Region* tmp_region_index = reinterpret_cast(regions.size()); + for (Province* province : new_region.get_provinces()) + province->region = tmp_region_index; + if (!error_message.empty()) { + error_message += SEPARATOR; + ret = FAILURE; } + error_message += "Added region: " + identifier; } - regions.push_back(new_region); - error_message += SEPARATOR + "Added region: " + identifier; - // Used to detect provinces listed in multiple regions, will - // be corrected once regions is stable (i.e. lock_regions). - Region* tmp_region_index = reinterpret_cast(regions.size()); - for (Province* province : new_region.get_provinces()) - province->region = tmp_region_index; - return SUCCESS; + if (ret != SUCCESS) error_message = "Error message for region: " + identifier + error_message; + return ret; } void Map::lock_regions() { @@ -161,6 +188,20 @@ Province const* Map::get_province_by_colour(Province::colour_t colour) const { return nullptr; } +Region* Map::get_region_by_identifier(std::string const& identifier) { + if (!identifier.empty()) + for (Region& region : regions) + if (region.get_identifier() == identifier) return ®ion; + return nullptr; +} + +Region const* Map::get_region_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Region const& region : regions) + if (region.get_identifier() == identifier) return ®ion; + return nullptr; +} + static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) { return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2]; } @@ -188,17 +229,13 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, std::vector province_checklist(provinces.size()); return_t ret = SUCCESS; - - error_message = "Error message for province index image generation:"; + std::unordered_set unrecognised_colours; + error_message.clear(); for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { const int32_t idx = x + y * width; const Province::colour_t colour = colour_at(colour_data, idx); - if (colour == Province::NULL_COLOUR) { - province_index_image[idx] = Province::NULL_INDEX; - continue; - } if (x > 0) { const int32_t jdx = idx - 1; if (colour_at(colour_data, jdx) == colour) { @@ -220,8 +257,11 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, province_checklist[index - 1] = true; continue; } - error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(x) + ")"; - ret = FAILURE; + if (unrecognised_colours.find(colour) == unrecognised_colours.end()) { + unrecognised_colours.insert(colour); + error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(y) + ")"; + ret = FAILURE; + } province_index_image[idx] = Province::NULL_INDEX; } } @@ -233,7 +273,8 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, } } - error_message += SEPARATOR + "Generated province index image"; + if (!error_message.empty()) error_message = "Error message for province index image generation:" + error_message + SEPARATOR; + error_message += "Generated province index image"; return ret; } @@ -259,11 +300,10 @@ return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t return FAILURE; } Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func }; - for (Mapmode const& mapmode : mapmodes) { - if (mapmode.get_identifier() == identifier) { - error_message = "Duplicate mapmode identifiers: " + mapmode.get_identifier() + " and " + identifier; - return FAILURE; - } + Mapmode const* old_mapmode = get_mapmode_by_identifier(identifier); + if (old_mapmode != nullptr) { + error_message = "Duplicate mapmode identifiers: " + old_mapmode->get_identifier() + " and " + identifier; + return FAILURE; } mapmodes.push_back(new_mapmode); error_message = "Added mapmode: " + identifier; @@ -295,12 +335,14 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, return FAILURE; } Mapmode const& mapmode = mapmodes[index]; - target += 3; // Skip past Province::NULL_INDEX + target += 4; // Skip past Province::NULL_INDEX for (Province const& province : provinces) { const Province::colour_t colour = mapmode.get_colour_func()(*this, province); *target++ = (colour >> 16) & 0xFF; *target++ = (colour >> 8) & 0xFF; *target++ = colour & 0xFF; + *target++ = province.is_water() ? 0 : 255; } + error_message = "Generated province colours for mapmode " + mapmode.get_identifier(); return SUCCESS; } diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp index 42963c9..73ab8fd 100644 --- a/extension/src/openvic2/Map.hpp +++ b/extension/src/openvic2/Map.hpp @@ -1,75 +1,24 @@ #pragma once -#include -#include #include #include -#include "Types.hpp" +#include "Region.hpp" namespace OpenVic2 { - struct Region; - struct Map; - /* REQUIREMENTS: - * MAP-43, MAP-47 - */ - struct Province { - friend struct Map; - - using colour_t = uint32_t; - using index_t = uint16_t; - - static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; - static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; - private: - index_t index; - std::string identifier; - colour_t colour; - Region* region = nullptr; - - Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); - public: - static std::string colour_to_hex_string(colour_t colour); - - index_t get_index() const; - std::string const& get_identifier() const; - colour_t get_colour() const; - Region* get_region() const; - std::string to_string() const; - }; - - /* REQUIREMENTS: - * MAP-6, MAP-44, MAP-48 - */ - struct Region { - friend struct Map; - private: - std::string identifier; - std::vector provinces; - - Region(std::string const& new_identifier); - public: - std::string const& get_identifier() const; - size_t get_province_count() const; - bool contains_province(Province const* province) const; - std::vector const& get_provinces() const; - }; - - struct Mapmode { + struct Mapmode : HasIdentifier { friend struct Map; using colour_func_t = std::function; using index_t = size_t; private: index_t index; - std::string identifier; colour_func_t colour_func; Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); public: index_t get_index() const; - std::string const& get_identifier() const; colour_func_t get_colour_func() const; }; @@ -80,7 +29,7 @@ namespace OpenVic2 { private: std::vector provinces; std::vector regions; - bool provinces_locked = false, regions_locked = false; + bool provinces_locked = false, water_provinces_locked = false, regions_locked = false; size_t width = 0, height = 0; std::vector province_index_image; @@ -88,10 +37,12 @@ namespace OpenVic2 { public: return_t add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message); void lock_provinces(); + return_t set_water_province(std::string const& identifier, std::string& error_message); + void lock_water_provinces(); return_t add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message); void lock_regions(); - size_t get_province_count() const; + size_t get_province_count() const; Province* get_province_by_index(Province::index_t index); Province const* get_province_by_index(Province::index_t index) const; Province* get_province_by_identifier(std::string const& identifier); @@ -99,6 +50,9 @@ namespace OpenVic2 { Province* get_province_by_colour(Province::colour_t colour); Province const* get_province_by_colour(Province::colour_t colour) const; + Region* get_region_by_identifier(std::string const& identifier); + Region const* get_region_by_identifier(std::string const& identifier) const; + return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message); size_t get_width() const; size_t get_height() const; diff --git a/extension/src/openvic2/Province.cpp b/extension/src/openvic2/Province.cpp index 49f1b0e..7d55708 100644 --- a/extension/src/openvic2/Province.cpp +++ b/extension/src/openvic2/Province.cpp @@ -1,4 +1,4 @@ -#include "Map.hpp" +#include "Province.hpp" #include #include @@ -7,9 +7,8 @@ using namespace OpenVic2; Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : - index(new_index), identifier(new_identifier), colour(new_colour) { + HasIdentifier(new_identifier), index(new_index), colour(new_colour) { assert(index != NULL_INDEX); - assert(!identifier.empty()); assert(colour != NULL_COLOUR); } @@ -23,10 +22,6 @@ Province::index_t Province::get_index() const { return index; } -std::string const& Province::get_identifier() const { - return identifier; -} - Province::colour_t Province::get_colour() const { return colour; } @@ -35,6 +30,14 @@ Region* Province::get_region() const { return region; } +bool Province::is_water() const { + return water; +} + +Province::life_rating_t Province::get_life_rating() const { + return life_rating; +} + std::string Province::to_string() const { - return "(#" + std::to_string(index) + ", " + identifier + ", 0x" + colour_to_hex_string(colour) + ")"; + return "(#" + std::to_string(index) + ", " + get_identifier() + ", 0x" + colour_to_hex_string(colour) + ")"; } diff --git a/extension/src/openvic2/Province.hpp b/extension/src/openvic2/Province.hpp new file mode 100644 index 0000000..deebd8c --- /dev/null +++ b/extension/src/openvic2/Province.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "Types.hpp" + +namespace OpenVic2 { + struct Region; + struct Map; + + /* REQUIREMENTS: + * MAP-5, MAP-8, MAP-43, MAP-47 + */ + struct Province : HasIdentifier { + friend struct Map; + + using colour_t = uint32_t; + using index_t = uint16_t; + using life_rating_t = int8_t; + + static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; + static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; + private: + index_t index; + colour_t colour; + Region* region = nullptr; + bool water = false; + life_rating_t life_rating = 0; + + Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); + public: + static std::string colour_to_hex_string(colour_t colour); + + index_t get_index() const; + colour_t get_colour() const; + Region* get_region() const; + bool is_water() const; + life_rating_t get_life_rating() const; + std::string to_string() const; + }; +} diff --git a/extension/src/openvic2/Region.cpp b/extension/src/openvic2/Region.cpp index 6ee05f5..67a75a9 100644 --- a/extension/src/openvic2/Region.cpp +++ b/extension/src/openvic2/Region.cpp @@ -1,26 +1,26 @@ -#include "Map.hpp" +#include "Region.hpp" #include #include using namespace OpenVic2; -Region::Region(std::string const& new_identifier) : identifier(new_identifier) { - assert(!identifier.empty()); -} - -std::string const& Region::get_identifier() const { - return identifier; -} - -size_t Region::get_province_count() const { +size_t ProvinceSet::get_province_count() const { return provinces.size(); } -bool Region::contains_province(Province const* province) const { +bool ProvinceSet::contains_province(Province const* province) const { return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); } -std::vector const& Region::get_provinces() const { +std::set const& ProvinceSet::get_provinces() const { return provinces; } + +Region::Region(std::string const& new_identifier) : HasIdentifier(new_identifier) {} + +Province::colour_t Region::get_colour() const { + if (provinces.empty()) return 0xFF0000; + Province const* province = *provinces.cbegin(); + return province->get_colour(); +} diff --git a/extension/src/openvic2/Region.hpp b/extension/src/openvic2/Region.hpp new file mode 100644 index 0000000..4ebabd1 --- /dev/null +++ b/extension/src/openvic2/Region.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "Province.hpp" + +namespace OpenVic2 { + struct Map; + + struct ProvinceSet { + protected: + std::set provinces; + public: + size_t get_province_count() const; + bool contains_province(Province const* province) const; + std::set const& get_provinces() const; + }; + + /* REQUIREMENTS: + * MAP-6, MAP-44, MAP-48 + */ + struct Region : HasIdentifier, ProvinceSet { + friend struct Map; + private: + Region(std::string const& new_identifier); + public: + Province::colour_t get_colour() const; + }; +} diff --git a/extension/src/openvic2/Types.cpp b/extension/src/openvic2/Types.cpp new file mode 100644 index 0000000..67c7a21 --- /dev/null +++ b/extension/src/openvic2/Types.cpp @@ -0,0 +1,13 @@ +#include "Types.hpp" + +#include + +using namespace OpenVic2; + +HasIdentifier::HasIdentifier(std::string const& new_identifier) : identifier(new_identifier) { + assert(!identifier.empty()); +} + +std::string const& HasIdentifier::get_identifier() const { + return identifier; +} diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp index 0fb1c8b..bf5ee27 100644 --- a/extension/src/openvic2/Types.hpp +++ b/extension/src/openvic2/Types.hpp @@ -1,7 +1,18 @@ #pragma once +#include + namespace OpenVic2 { using return_t = bool; // This mirrors godot::Error, where `OK = 0` and `FAILED = 1`. static const return_t SUCCESS = false, FAILURE = true; + + struct HasIdentifier { + private: + std::string identifier; + protected: + HasIdentifier(std::string const& new_identifier); + public: + std::string const& get_identifier() const; + }; } diff --git a/game/art/terrain/farmlands.png b/game/art/terrain/farmlands.png new file mode 100644 index 0000000..3702ad0 Binary files /dev/null and b/game/art/terrain/farmlands.png differ diff --git a/game/art/terrain/farmlands.png.import b/game/art/terrain/farmlands.png.import new file mode 100644 index 0000000..4a06b1f --- /dev/null +++ b/game/art/terrain/farmlands.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ckf222w5usrsu" +path="res://.godot/imported/farmlands.png-821213ab9dba19cea6f6c966b3a3760b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://art/terrain/farmlands.png" +dest_files=["res://.godot/imported/farmlands.png-821213ab9dba19cea6f6c966b3a3760b.ctex"] + +[params] + +compress/mode=3 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=2 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=false +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/art/terrain/terrain.png b/game/art/terrain/terrain.png deleted file mode 100644 index 6d36dee..0000000 Binary files a/game/art/terrain/terrain.png and /dev/null differ diff --git a/game/art/terrain/terrain.png.import b/game/art/terrain/terrain.png.import deleted file mode 100644 index d7a078f..0000000 --- a/game/art/terrain/terrain.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmw0pvjthnn8c" -path="res://.godot/imported/terrain.png-06c63c2b87b3131a2067f668f87a9d67.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://art/terrain/terrain.png" -dest_files=["res://.godot/imported/terrain.png-06c63c2b87b3131a2067f668f87a9d67.ctex"] - -[params] - -compress/mode=3 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=2 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=false -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/game/common/map/provinces.json b/game/common/map/provinces.json index 66de29b..71be5cb 100644 --- a/game/common/map/provinces.json +++ b/game/common/map/provinces.json @@ -2,8 +2,222 @@ "prov_britain": [150, 0, 0], "prov_ireland": [23, 147, 31], "prov_iceland": "343D91", + "prov_corsica": "FFD800", + "prov_sardinia": "00FFFF", + "prov_sicily": "FFA13D", + "prov_malta": "96E6FF", + "prov_cyprus": "FFE682", + "prov_greenland": "7A66FF", + "prov_baleares": "FF9E21", + "prov_gotland": "8300FF", + "prov_crete": "FF3523", + "prov_jan_mayen": "003FFF", + "prov_faroes": "964B00", + "prov_mann": "935575", + "prov_shetlands": "916F7D", + "prov_orkney": "8E1C70", + "prov_channel_islands": "8C6267", + "prov_madiera": "87580C", + "prov_canarias": "843740", + "prov_sjaeland": "820B02", + "prov_bornholm": "7F512F", + "prov_bear_island": "AE2AD6", + "prov_pantelleria": "FFA575", + "prov_iberia": "FF425D", + "prov_scandinavia": "005F32", + "prov_jutland": "B7004B", + "prov_fyn": "B55C63", + "prov_hiiumaa": "52FFB2", + "prov_saaremaa": "B5E31D", + "prov_italy": "47872C", + "prov_elba": "333333", + "prov_france": "0B0BC6", + "prov_netherlands": "FF472C", + "prov_belgium": "8C6A16", + "prov_luxembourg": "8FB7C6", + "prov_switzerland": "A50000", + "prov_balkans": "00FF5D", + "prov_crimea": "752179", + "prov_germany": "303030", + "prov_poland": "C90043", + "prov_baltics": "6327C4", + "prov_finland": "E8E8E8", + "prov_aland": "8769B3", + "prov_ukraine": "C1CB00", + "prov_russia": "006311", + + "prov_north_america": "A114FF", "prov_cuba": "1E29FF", + "prov_nova_scotia": "1115FF", + "prov_bermuda": "FF2370", + "prov_jamaica": "329600", + "prov_hispaniola": "742B7C", + "prov_aleutians": "FF07AC", + "prov_bahamas": "824261", + "prov_turks_and_caicos": "7F4424", + "prov_puerto_rico": "0D7C57", + "prov_barbados": "747A48", + "prov_grenada": "32774B", + "prov_st_vincent": "535C75", + "prov_st_lucia": "E15CEE", + "prov_martinique": "EDB274", + "prov_dominica": "EAE77E", + "prov_guadeloupe": "E8279E", + "prov_montserrat": "80AAE5", + "prov_antigua": "E2AEB9", + "prov_barbuda": "E0966D", + "prov_st_kitts": "DD85DA", + "prov_west_virgin_islands": "304716", + "prov_east_virgin_islands": "44321E", + "prov_cayman_islands": "FF7900", + "prov_angulia": "FF3D57", + "prov_central_america": "005B5E", + "prov_mexico": "3BA533", + + "prov_south_america": "2F7A22", + "prov_galapagos": "638293", + "prov_falklands": "91451F", + "prov_south_georgia": "8E8B8E", + + "prov_africa": "7F3300", "prov_madagascar": "790091", + "prov_socotra": "89801A", + "prov_mauritius": "1C8400", + "prov_reunion": "7D821F", + "prov_comoros": "7F5731", + "prov_sao_tome": "FFAFE8", + "prov_fernando_po": "FF665B", + "prov_cape_verde": "00FF48", + "prov_ascension": "7C3B3E", + "prov_st_helena": "7A6C48", + "prov_tristan_da_cunha": "77680E", + "prov_seychelles": "EF68FF", + "prov_prince_edward_islands": "826F68", + "prov_kerguelen_islands": "671F7F", + "prov_heard_island": "7C4244", + "prov_egypt": "A5815B", + "prov_morocco": "D44509", + + "prov_middle_east": "615EA8", "prov_ceylon": "FF6A00", - "prov_formosa": "82B1FF" + "prov_formosa": "82B1FF", + "prov_sakhalin": "006421", + "prov_maldives": "DC0000", + "prov_hainan": "688785", + "prov_hokkaido": "BA0DB5", + "prov_diego_garcia": "752268", + "prov_philippines": "FFA5AD", + "prov_india": "720041", + "prov_andamans": "706054", + "prov_nicobar_islands": "30006B", + "prov_indochina": "007272", + "prov_korea": "1E2570", + "prov_okinawa": "216D38", + "prov_yaeyama": "6B120A", + "prov_kyushu": "9E2521", + "prov_shikoku": "6F9B61", + "prov_japan": "99581B", + "prov_kurils": "992B15", + "prov_manchuria": "B79900", + "prov_china": "B57A53", + "prov_central_asia": "00B2B2", + "prov_siberia": "000EAF", + "prov_iran": "703E1D", + "prov_anatolia": "A81000", + + "prov_oceania": "FF4C00", + "prov_indonesia": "A56A9E", + "prov_north_island": "DB41AF", + "prov_south_island": "D86E47", + "prov_tasmania": "D6BF2C", + "prov_australia": "5BB1D3", + "prov_hawaii": "008C5D", + + "prov_aral_sea": "AA61C6", + "prov_caspian_sea": "00C413", + "prov_lake_ladoga": "462A64", + "prov_lake_ontario": "46CD64", + "prov_lake_erie": "9F2663", + "prov_lake_huron": "9FC6EA", + "prov_lake_michigan": "9FC62A", + "prov_lake_superior": "9F352A", + "prov_lake_baikal": "B51453", + "prov_lake_woods": "9F892A", + "prov_lake_manitoba": "FF0071", + "prov_reindeer_lake": "FF7DFF", + "prov_lake_ronge": "D9FF51", + "prov_lake_athabasca": "FF7D3D", + "prov_great_slave_lake": "49FF6B", + "prov_great_bear_lake": "FFC6C9", + + "prov_azov_sea": "3E33FF", + "prov_black_sea": "3EE1FF", + "prov_marmara_sea": "00009D", + "prov_agean_sea": "0019FF", + "prov_ionian_sea": "003A9D", + "prov_adriatic_sea": "00E3FF", + "prov_tyrrhenian_sea": "0935FF", + "prov_east_mediterranean": "00BBFF", + "prov_central_mediterranean": "3A5FDC", + "prov_west_mediterranean": "93C5FF", + "prov_ligurian_sea": "0000B0", + "prov_balearic_sea": "001BFF", + "prov_alboran_sea": "3E98FF", + "prov_gulf_bothnia": "52E39D", + "prov_gulf_finland": "0935C2", + "prov_gulf_riga": "004987", + "prov_baltic_sea": "5BC5CB", + "prov_danish_straits": "004DB0", + "prov_english_channel": "0079FF", + "prov_irish_sea": "544DFF", + "prov_biscay_bay": "93EEFF", + "prov_north_sea": "31BBFF", + "prov_red_sea": "0952FF", + "prov_arabian_sea": "00007E", + "prov_persian_gulf": "3EA3FF", + "prov_andaman_sea": "0092FF", + "prov_bay_bengal": "4075FF", + "prov_okhotsk_sea": "66C5FF", + "prov_japan_sea": "3A92DC", + "prov_east_china_sea": "0066CB", + "prov_south_china_sea": "3EEEFF", + "prov_philippine_sea": "210066", + "prov_celebes_sea": "0066BB", + "prov_java_sea": "3E33C9", + "prov_banda_sea": "73A3FF", + "prov_arafura_sea": "0000D4", + "prov_gulf_mexico": "00639D", + "prov_caribbean_sea": "00C2DA", + "prov_mozambique_channel": "098FFF", + "prov_zanj_sea": "93B5FF", + "prov_kara_sea": "49FFFF", + "prov_barents_sea": "3A40DC", + "prov_norwegian_sea": "000087", + "prov_greenland_sea": "33EEFF", + "prov_labrador_sea": "003787", + "prov_hudson_bay": "93F7FF", + "prov_gulf_st_lawrence": "4DF7FF", + "prov_gulf_alaska": "2C2F87", + "prov_gulf_california": "2C2FCF", + "prov_east_siberian_sea": "52E3FF", + "prov_sargasso_sea": "0019DA", + "prov_gulf_guinea": "008BDA", + "prov_celtic_sea": "0050B0", + "prov_argentine_sea": "0082B0", + "prov_chilean_sea": "47FFFF", + "prov_north_atlantic": "00B3FF", + "prov_central_atlantic": "68C5FF", + "prov_south_atlantic": "004DDA", + "prov_indian_ocean": "000066", + "prov_great_australian_bight": "3A75FF", + "prov_tasman_sea": "002CD4", + "prov_coral_sea": "8919FF", + "prov_melanesia": "3AA8FF", + "prov_micronesia": "0098CB", + "prov_polynesia": "003EDA", + "prov_north_pacific": "00EECF", + "prov_south_pacific": "03B3FF", + "prov_bering_sea": "0049DA", + "prov_chukchi_sea": "0087A5", + "prov_beaufort_sea": "93BEFF" } diff --git a/game/common/map/provinces.png b/game/common/map/provinces.png index 68bf528..73cc33c 100644 Binary files a/game/common/map/provinces.png and b/game/common/map/provinces.png differ diff --git a/game/common/map/regions.json b/game/common/map/regions.json index bbeeb56..1684fb5 100644 --- a/game/common/map/regions.json +++ b/game/common/map/regions.json @@ -1,6 +1,13 @@ { - "region_europe": ["prov_britain", "prov_ireland", "prov_iceland"], - "region_america": ["prov_cuba"], - "region_africa": ["prov_madagascar"], - "region_asia": ["prov_ceylon", "prov_formosa"] + "region_europe": ["prov_britain", "prov_ireland", "prov_iceland", "prov_corsica", "prov_sardinia", "prov_sicily", "prov_malta", "prov_cyprus", "prov_greenland", "prov_baleares", "prov_gotland", "prov_crete", "prov_jan_mayen", "prov_faroes", "prov_mann", "prov_shetlands", "prov_orkney", "prov_channel_islands", "prov_madiera", "prov_canarias", "prov_sjaeland", "prov_bornholm", "prov_bear_island", "prov_pantelleria", "prov_iberia", "prov_scandinavia", "prov_jutland", "prov_fyn", "prov_hiiumaa", "prov_saaremaa", "prov_italy", "prov_elba", "prov_france", "prov_netherlands", "prov_belgium", "prov_luxembourg", "prov_switzerland", "prov_balkans", "prov_crimea", "prov_germany", "prov_poland", "prov_baltics", "prov_finland", "prov_aland", "prov_ukraine", "prov_russia"], + + "region_north_america": ["prov_north_america", "prov_cuba", "prov_nova_scotia", "prov_bermuda", "prov_jamaica", "prov_hispaniola", "prov_aleutians", "prov_bahamas", "prov_turks_and_caicos", "prov_puerto_rico", "prov_barbados", "prov_grenada", "prov_st_vincent", "prov_st_lucia", "prov_martinique", "prov_dominica", "prov_guadeloupe", "prov_montserrat", "prov_antigua", "prov_barbuda", "prov_st_kitts", "prov_west_virgin_islands", "prov_east_virgin_islands", "prov_cayman_islands", "prov_angulia", "prov_central_america", "prov_mexico"], + + "region_south_america": ["prov_south_america", "prov_galapagos", "prov_falklands", "prov_south_georgia"], + + "region_africa": ["prov_africa", "prov_madagascar", "prov_socotra", "prov_mauritius", "prov_reunion", "prov_comoros", "prov_sao_tome", "prov_fernando_po", "prov_cape_verde", "prov_ascension", "prov_st_helena", "prov_tristan_da_cunha", "prov_seychelles", "prov_prince_edward_islands", "prov_kerguelen_islands", "prov_heard_island", "prov_egypt", "prov_morocco"], + + "region_asia": ["prov_middle_east", "prov_ceylon", "prov_formosa", "prov_sakhalin", "prov_maldives", "prov_hainan", "prov_hokkaido", "prov_diego_garcia", "prov_philippines", "prov_india", "prov_andamans", "prov_nicobar_islands", "prov_indochina", "prov_korea", "prov_okinawa", "prov_yaeyama", "prov_kyushu", "prov_shikoku", "prov_japan", "prov_kurils", "prov_manchuria", "prov_china", "prov_central_asia", "prov_siberia", "prov_iran", "prov_anatolia"], + + "region_oceania": ["prov_indonesia", "prov_north_island", "prov_south_island", "prov_tasmania", "prov_australia", "prov_hawaii", "prov_oceania"] } diff --git a/game/common/map/water.json b/game/common/map/water.json new file mode 100644 index 0000000..fda53a9 --- /dev/null +++ b/game/common/map/water.json @@ -0,0 +1,6 @@ + +[ + "prov_aral_sea", "prov_caspian_sea", "prov_lake_ladoga", "prov_lake_ontario", "prov_lake_erie", "prov_lake_huron", "prov_lake_michigan", "prov_lake_superior", "prov_lake_baikal", "prov_lake_woods", "prov_lake_manitoba", "prov_reindeer_lake", "prov_lake_ronge", "prov_lake_athabasca", "prov_great_slave_lake", "prov_great_bear_lake", + + "prov_azov_sea", "prov_black_sea", "prov_marmara_sea", "prov_agean_sea", "prov_ionian_sea", "prov_adriatic_sea", "prov_tyrrhenian_sea", "prov_east_mediterranean", "prov_central_mediterranean", "prov_west_mediterranean", "prov_ligurian_sea", "prov_balearic_sea", "prov_alboran_sea", "prov_gulf_bothnia", "prov_gulf_finland", "prov_gulf_riga", "prov_baltic_sea", "prov_danish_straits", "prov_english_channel", "prov_irish_sea", "prov_biscay_bay", "prov_north_sea", "prov_red_sea", "prov_arabian_sea", "prov_persian_gulf", "prov_andaman_sea", "prov_bay_bengal", "prov_okhotsk_sea", "prov_japan_sea", "prov_east_china_sea", "prov_south_china_sea", "prov_philippine_sea", "prov_celebes_sea", "prov_java_sea", "prov_banda_sea", "prov_arafura_sea", "prov_gulf_mexico", "prov_caribbean_sea", "prov_mozambique_channel", "prov_zanj_sea", "prov_kara_sea", "prov_barents_sea", "prov_norwegian_sea", "prov_greenland_sea", "prov_labrador_sea", "prov_hudson_bay", "prov_gulf_st_lawrence", "prov_gulf_alaska", "prov_gulf_california", "prov_east_siberian_sea", "prov_sargasso_sea", "prov_gulf_guinea", "prov_celtic_sea", "prov_argentine_sea", "prov_chilean_sea", "prov_north_atlantic", "prov_central_atlantic", "prov_south_atlantic", "prov_indian_ocean", "prov_great_australian_bight", "prov_tasman_sea", "prov_coral_sea", "prov_melanesia", "prov_micronesia", "prov_polynesia", "prov_north_pacific", "prov_south_pacific", "prov_bering_sea", "prov_chukchi_sea", "prov_beaufort_sea" +] diff --git a/game/localisation/en_GB/mapmodes.csv b/game/localisation/en_GB/mapmodes.csv index c5b1bb0..440175f 100644 --- a/game/localisation/en_GB/mapmodes.csv +++ b/game/localisation/en_GB/mapmodes.csv @@ -2,4 +2,5 @@ ,, Test Mapmodes mapmode_province,Province Mapmode mapmode_region,Region Mapmode +mapmode_terrain,Terrain Mapmode mapmode_index,Index Mapmode diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv index b483662..33e5c42 100644 --- a/game/localisation/en_GB/menus.csv +++ b/game/localisation/en_GB/menus.csv @@ -49,5 +49,17 @@ GAMELOBBY_START,Start Game GAMELOBBY_BACK,Back ,, Game Session Menu -GAMESESSIONMENU_RESIGN,Resign +GAMESESSIONMENU_SAVE,Save Game +GAMESESSIONMENU_LOAD,Load Game +GAMESESSIONMENU_OPTIONS,Options +GAMESESSIONMENU_MAINMENU,Resign +GAMESESSIONMENU_QUIT,Quit GAMESESSIONMENU_CLOSE,Close + +GAMESESSIONMENU_MAINMENU_DIALOG_TITLE,Resign Game +GAMESESSIONMENU_MAINMENU_DIALOG_TEXT,Are you sure you want to resign and return to the main menu? +GAMESESSIONMENU_QUIT_DIALOG_TITLE,Quit Game +GAMESESSIONMENU_QUIT_DIALOG_TEXT,Are you sure you want to quit and return to desktop? + +DIALOG_OK,OK +DIALOG_CANCEL,Cancel diff --git a/game/localisation/en_GB/provinces.csv b/game/localisation/en_GB/provinces.csv index 3b47955..24248a0 100644 --- a/game/localisation/en_GB/provinces.csv +++ b/game/localisation/en_GB/provinces.csv @@ -1,9 +1,230 @@ -,, Test Provinces +,, Europe prov_britain_NAME,Britain prov_ireland_NAME,Ireland prov_iceland_NAME,Iceland +prov_corsica_NAME,Corsica +prov_sardinia_NAME,Sardinia +prov_sicily_NAME,Sicily +prov_malta_NAME,Malta +prov_cyprus_NAME,Cyprus +prov_greenland_NAME,Greenland +prov_baleares_NAME,Balearic Islands +prov_gotland_NAME,Gotland +prov_crete_NAME,Crete +prov_jan_mayen_NAME,Jan Mayen +prov_faroes_NAME,Faroe Islands +prov_mann_NAME,Isle of Mann +prov_shetlands_NAME,Shetlands +prov_orkney_NAME,Orkney +prov_channel_islands_NAME,Channel Islands +prov_madiera_NAME,Madiera +prov_canarias_NAME,Canarias +prov_sjaeland_NAME,Sjaeland +prov_bornholm_NAME,Bornholm +prov_bear_island_NAME,Bear Island +prov_pantelleria_NAME,Pantelleria +prov_iberia_NAME,Iberia +prov_scandinavia_NAME,Scandinavia +prov_jutland_NAME,Jutland +prov_fyn_NAME,Fyn +prov_hiiumaa_NAME,Hiiumaa +prov_saaremaa_NAME,Saaremaa +prov_italy_NAME,Italy +prov_elba_NAME,Elba +prov_france_NAME,France +prov_netherlands_NAME,Netherlands +prov_belgium_NAME,Belgium +prov_luxembourg_NAME,Luxembourg +prov_switzerland_NAME,Switzerland +prov_balkans_NAME,Balkans +prov_crimea_NAME,Crimea +prov_germany_NAME,Germany +prov_poland_NAME,Poland +prov_baltics_NAME,Baltics +prov_finland_NAME,Finland +prov_aland_NAME,Åland +prov_ukraine_NAME,Ukraine +prov_russia_NAME,Russia + +,, North America +prov_north_america_NAME,North America prov_cuba_NAME,Cuba +prov_nova_scotia_NAME,Nova Scotia +prov_bermuda_NAME,Bermuda +prov_jamaica_NAME,Jamaica +prov_hispaniola_NAME,Hispaniola +prov_aleutians_name,Aleutian Islands +prov_bahamas_NAME,Bahamas +prov_turks_and_caicos_NAME,Turks and Caicos +prov_puerto_rico_NAME,Puerto Rico +prov_barbados_NAME,Barbados +prov_grenada_NAME,Grenada +prov_st_vincent_NAME,St Vincent +prov_st_lucia_NAME,St Lucia +prov_martinique_NAME,Martinique +prov_dominica_NAME,Dominica +prov_guadeloupe_NAME,Guadeloupe +prov_montserrat_NAME,Montserrat +prov_antigua_NAME,Antigua +prov_barbuda_NAME,Barbuda +prov_st_kitts_NAME,St Kitts +prov_west_virgin_islands_NAME,West Virgin Islands +prov_east_virgin_islands_NAME,East Virgin Islands +prov_cayman_islands_NAME,Cayman Islands +prov_angulia_NAME,Angulia +prov_central_america_NAME,Central America +prov_mexico_NAME,Mexico + +,, South America +prov_south_america_NAME,South America +prov_galapagos_NAME,Galapagos +prov_falklands_NAME,Falklands +prov_south_georgia_NAME,South Georgia + +,, Africa +prov_africa_NAME,Africa prov_madagascar_NAME,Madagascar +prov_socotra_NAME,Socotra +prov_mauritius_NAME,Mauritius +prov_reunion_NAME,Réunion +prov_comoros_NAME,Comoros +prov_sao_tome_NAME,Sao Tome +prov_fernando_po_NAME,Fernando Po +prov_cape_verde_NAME,Cape Verde +prov_ascension_NAME,Ascension +prov_st_helena_NAME,St Helena +prov_tristan_da_cunha_NAME,Tristan da Cunha +prov_seychelles_NAME,Seychelles +prov_prince_edward_islands_NAME,Prince Edward Islands +prov_kerguelen_islands_NAME,Kerguelen Islands +prov_heard_island_NAME,Heard Island +prov_egypt_NAME,Egypt +prov_morocco_NAME,Morocco + +,, Asia +prov_middle_east_NAME,Middle East prov_ceylon_NAME,Ceylon prov_formosa_NAME,Formosa +prov_sakhalin_NAME,Sakhalin +prov_maldives_NAME,Maldives +prov_hainan_NAME,Hainan +prov_hokkaido_NAME,Hokkaido +prov_diego_garcia_NAME,Diego Garcia +prov_philippines_NAME,Philippines +prov_india_NAME,India +prov_andamans_NAME,Andaman Islands +prov_nicobar_islands_NAME,Nicobar Islands +prov_indochina_NAME,Indochina +prov_korea_NAME,Korea +prov_okinawa_NAME,Okinawa +prov_yaeyama_NAME,Yaeyama +prov_kyushu_NAME,Kyushu +prov_shikoku_NAME,Shikoku +prov_japan_NAME,Japan +prov_kurils_NAME,Kuril Islands +prov_manchuria_NAME,Manchuria +prov_china_NAME,China +prov_central_asia_NAME,Central Asia +prov_siberia_NAME,Siberia +prov_iran_NAME,Iran +prov_anatolia_NAME,Anatolia + +,, Oceania +prov_oceania_NAME,Oceania +prov_indonesia_NAME,Indonesia +prov_north_island_NAME,North Island +prov_south_island_NAME,South Island +prov_tasmania_NAME,Tasmania +prov_australia_NAME,Australia +prov_hawaii_NAME,Hawaii + +,, Lakes +prov_aral_sea_NAME,Aral Sea +prov_caspian_sea_NAME,Caspian Sea +prov_lake_ladoga_NAME,Lake Ladoga +prov_lake_ontario_NAME,Lake Ontario +prov_lake_erie_NAME,Lake Erie +prov_lake_huron_NAME,Lake Huron +prov_lake_michigan_NAME,Lake Michigan +prov_lake_superior_NAME,Lake Superior +prov_lake_baikal_NAME,Lake Baikal +prov_lake_woods_NAME,Lake of the Woods +prov_lake_manitoba_NAME,Lake Manitoba +prov_reindeer_lake_NAME,Reindeer Lake +prov_lake_ronge_NAME,Lac la Ronge +prov_lake_athabasca_NAME,Lake Athabasca +prov_great_slave_lake_NAME,Great Slave Lake +prov_great_bear_lake_NAME,Great Bear Lake + +,, Seas and Oceans +prov_azov_sea_NAME,Sea of Azov +prov_black_sea_NAME,Black Sea +prov_marmara_sea_NAME,Sea of Marmara +prov_agean_sea_NAME,Agean Sea +prov_ionian_sea_NAME,Ionian Sea +prov_adriatic_sea_NAME,Adriatic Sea +prov_tyrrhenian_sea_NAME,Tyrrhenian Sea +prov_east_mediterranean_NAME,East Mediterranean Sea +prov_central_mediterranean_NAME,Central Mediterranean Sea +prov_west_mediterranean_NAME,West Mediterranean Sea +prov_ligurian_sea_NAME,Ligurian Sea +prov_balearic_sea_NAME,Balearic Sea +prov_alboran_sea_NAME,Alboran Sea +prov_gulf_bothnia_NAME,Gulf of Bothnia +prov_gulf_finland_NAME,Gulf of Finland +prov_gulf_riga_NAME,Gulf of Riga +prov_baltic_sea_NAME,Baltic Sea +prov_danish_straits_NAME,Danish Straits +prov_english_channel_NAME,English Channel +prov_irish_sea_NAME,Irish Sea +prov_biscay_bay_NAME,Bay of Biscay +prov_north_sea_NAME,North Sea +prov_red_sea_NAME,Red Sea +prov_arabian_sea_NAME,Arabian Sea +prov_persian_gulf_NAME,Persian Gulf +prov_andaman_sea_NAME,Andaman Sea +prov_bay_bengal_NAME,Bay of Bengal +prov_okhotsk_sea_NAME,Sea of Okhotsk +prov_japan_sea_NAME,Sea of Japan +prov_east_china_sea_NAME,East China Sea +prov_south_china_sea_NAME,South China Sea +prov_philippine_sea_NAME,Philippine Sea +prov_celebes_sea_NAME,Celebes Sea +prov_java_sea_NAME,Java Sea +prov_banda_sea_NAME,Banda Sea +prov_arafura_sea_NAME,Arafura Sea +prov_gulf_mexico_NAME,Gulf of Mexico +prov_caribbean_sea_NAME,Caribbean Sea +prov_mozambique_channel_NAME,Mozambique Channel +prov_zanj_sea_NAME,Sea of Zanj +prov_kara_sea_NAME,Kara Sea +prov_barents_sea_NAME,Barents Sea +prov_norwegian_sea_NAME,Norwegian Sea +prov_greenland_sea_NAME,Greenland Sea +prov_labrador_sea_NAME,Labrador Sea +prov_hudson_bay_NAME,Hudson Bay +prov_gulf_st_lawrence_NAME,Gulf of St Lawrence +prov_gulf_alaska_NAME,Gulf of Alaska +prov_gulf_california_NAME,Gulf of California +prov_east_siberian_sea_NAME,East Siberian Sea +prov_sargasso_sea_NAME,Sargasso Sea +prov_gulf_guinea_NAME,Gulf of Guinea +prov_celtic_sea_NAME,Celtic Sea +prov_argentine_sea_NAME,Argentine Sea +prov_chilean_sea_NAME,Chilean Sea +prov_north_atlantic_NAME,North Atlantic Ocean +prov_central_atlantic_NAME,Central Atlantic Ocean +prov_south_atlantic_NAME,South Atlantic Ocean +prov_indian_ocean_NAME,Indian Ocean +prov_great_australian_bight_NAME,Great Australian Bight +prov_tasman_sea_NAME,Tasman Sea +prov_coral_sea_NAME,Coral Sea +prov_melanesia_NAME,Melanesia +prov_micronesia_NAME,Micronesia +prov_polynesia_NAME,Polynesia +prov_north_pacific_NAME,North Pacific Ocean +prov_south_pacific_NAME,South Pacific Ocean +prov_bering_sea_NAME,Bering Sea +prov_chukchi_sea_NAME,Chukchi Sea +prov_beaufort_sea_NAME,Beaufort Sea diff --git a/game/localisation/en_GB/regions.csv b/game/localisation/en_GB/regions.csv new file mode 100644 index 0000000..8fe8943 --- /dev/null +++ b/game/localisation/en_GB/regions.csv @@ -0,0 +1,8 @@ + +,, Regions +region_europe_NAME,Europe +region_north_america_NAME,North America +region_south_america_NAME,South America +region_africa_NAME,Africa +region_asia_NAME,Asia +region_oceania_NAME,Oceania diff --git a/game/localisation/en_GB/regions.csv.import b/game/localisation/en_GB/regions.csv.import new file mode 100644 index 0000000..8dd0c09 --- /dev/null +++ b/game/localisation/en_GB/regions.csv.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/game/localisation/en_US/menus.csv b/game/localisation/en_US/menus.csv index 27a0858..807d1cb 100644 --- a/game/localisation/en_US/menus.csv +++ b/game/localisation/en_US/menus.csv @@ -1,3 +1,4 @@ + ,, Main Menu MAINMENU_TITLE,OpenVic2 MAINMENU_NEW_GAME,New Game @@ -48,5 +49,9 @@ GAMELOBBY_START,Start Game GAMELOBBY_BACK,Back ,, Game Session Menu -GAMESESSIONMENU_RESIGN,Resign +GAMESESSIONMENU_SAVE,Save Game +GAMESESSIONMENU_LOAD,Load Game +GAMESESSIONMENU_OPTIONS,Options +GAMESESSIONMENU_MAINMENU,Resign +GAMESESSIONMENU_QUIT,Quit GAMESESSIONMENU_CLOSE,Close diff --git a/game/localisation/fr_FR/menus.csv b/game/localisation/fr_FR/menus.csv index 8e8a7ad..0d84b64 100644 --- a/game/localisation/fr_FR/menus.csv +++ b/game/localisation/fr_FR/menus.csv @@ -1,3 +1,4 @@ + ,, Main Menu MAINMENU_TITLE,OpenVic2 MAINMENU_NEW_GAME,Nouveau Jeu @@ -48,5 +49,9 @@ GAMELOBBY_START,Démarrer Jeu GAMELOBBY_BACK,Retourner ,, Game Session Menu -GAMESESSIONMENU_RESIGN,Démissionner +GAMESESSIONMENU_SAVE,Sauvegarder la Partie +GAMESESSIONMENU_LOAD,Charger la Partie +GAMESESSIONMENU_OPTIONS,Options +GAMESESSIONMENU_MAINMENU,Démissionner +GAMESESSIONMENU_QUIT,Quitter GAMESESSIONMENU_CLOSE,Fermer diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index f4aac70..dbd3f9f 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -4,14 +4,17 @@ var Options = preload("Events/Options.gd").new() var Localisation = preload("Events/Localisation.gd").new() const _province_identifier_file : String = "res://common/map/provinces.json" +const _water_province_file : String = "res://common/map/water.json" const _region_file : String = "res://common/map/regions.json" const _province_shape_file : String = "res://common/map/provinces.png" # REQUIREMENTS -# * FS-333, FS-335, FS-341 +# * FS-333, FS-334, FS-335, FS-341 func _ready(): if MapSingleton.load_province_identifier_file(_province_identifier_file) != OK: push_error("Failed to load province identifiers") + if MapSingleton.load_water_province_file(_water_province_file) != OK: + push_error("Failed to load water provinces") if MapSingleton.load_region_file(_region_file) != OK: push_error("Failed to load regions") if MapSingleton.load_province_shape_file(_province_shape_file) != OK: diff --git a/game/src/GameSession/GameSession.gd b/game/src/GameSession/GameSession.gd index 38eaba1..fe83a8a 100644 --- a/game/src/GameSession/GameSession.gd +++ b/game/src/GameSession/GameSession.gd @@ -1,16 +1,11 @@ -extends Node +extends Control @export var _game_session_menu : Control func _ready(): - print("GameSession ready") + Events.Options.load_settings_from_file() # REQUIREMENTS: # * SS-42 func _on_game_session_menu_button_pressed(): _game_session_menu.visible = !_game_session_menu.visible - -# REQUIREMENTS: -# * SS-64 -func _on_game_session_menu_close_button_pressed(): - _game_session_menu.hide() diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index e270f8a..d23cb6c 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -1,13 +1,21 @@ -[gd_scene load_steps=6 format=3 uid="uid://bgnupcshe1m7r"] +[gd_scene load_steps=7 format=3 uid="uid://bgnupcshe1m7r"] [ext_resource type="Script" path="res://src/GameSession/GameSession.gd" id="1_eklvp"] [ext_resource type="PackedScene" uid="uid://g524p8lr574w" path="res://src/GameSession/MapControlPanel.tscn" id="3_afh6d"] [ext_resource type="PackedScene" uid="uid://dvdynl6eir40o" path="res://src/GameSession/GameSessionMenu.tscn" id="3_bvmqh"] [ext_resource type="PackedScene" uid="uid://dkehmdnuxih2r" path="res://src/GameSession/MapView.tscn" id="4_xkg5j"] [ext_resource type="PackedScene" uid="uid://byq323jbel48u" path="res://src/GameSession/ProvinceOverviewPanel.tscn" id="5_osjnn"] +[ext_resource type="PackedScene" uid="uid://cnbfxjy1m6wja" path="res://src/OptionMenu/OptionsMenu.tscn" id="6_p5mnx"] -[node name="GameSession" type="Node" node_paths=PackedStringArray("_game_session_menu")] +[node name="GameSession" type="Control" node_paths=PackedStringArray("_game_session_menu")] editor_description = "SS-102, UI-546" +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 script = ExtResource("1_eklvp") _game_session_menu = NodePath("GameSessionMenu") @@ -15,6 +23,7 @@ _game_session_menu = NodePath("GameSessionMenu") [node name="GameSessionMenu" parent="." instance=ExtResource("3_bvmqh")] visible = false +layout_mode = 1 anchors_preset = 8 anchor_left = 0.5 anchor_top = 0.5 @@ -24,28 +33,31 @@ grow_horizontal = 2 grow_vertical = 2 [node name="MapControlPanel" parent="." instance=ExtResource("3_afh6d")] +layout_mode = 1 anchors_preset = 3 anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 -offset_left = -350.0 -offset_top = -210.0 grow_horizontal = 0 grow_vertical = 0 [node name="ProvinceOverviewPanel" parent="." instance=ExtResource("5_osjnn")] -anchors_preset = -1 -anchor_top = 0.583333 -anchor_right = 0.15625 -offset_top = 0.0 -offset_right = 0.0 +layout_mode = 1 + +[node name="OptionsMenu" parent="." instance=ExtResource("6_p5mnx")] +visible = false +layout_mode = 1 [connection signal="map_view_camera_changed" from="MapView" to="MapControlPanel" method="_on_map_view_camera_changed"] [connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] -[connection signal="close_button_pressed" from="GameSessionMenu" to="." method="_on_game_session_menu_close_button_pressed"] +[connection signal="options_button_pressed" from="GameSessionMenu" to="OptionsMenu" method="show"] [connection signal="game_session_menu_button_pressed" from="MapControlPanel" to="." method="_on_game_session_menu_button_pressed"] [connection signal="mapmode_changed" from="MapControlPanel" to="MapView" method="_update_colour_texture"] [connection signal="minimap_clicked" from="MapControlPanel" to="MapView" method="_on_minimap_clicked"] [connection signal="mouse_entered" from="MapControlPanel" to="MapView" method="_on_mouse_exited_viewport"] [connection signal="mouse_exited" from="MapControlPanel" to="MapView" method="_on_mouse_entered_viewport"] +[connection signal="zoom_in_button_pressed" from="MapControlPanel" to="MapView" method="zoom_in"] +[connection signal="zoom_out_button_pressed" from="MapControlPanel" to="MapView" method="zoom_out"] +[connection signal="back_button_pressed" from="OptionsMenu" to="MapView" method="enable_processing"] +[connection signal="back_button_pressed" from="OptionsMenu" to="OptionsMenu" method="hide"] diff --git a/game/src/GameSession/GameSessionMenu.gd b/game/src/GameSession/GameSessionMenu.gd index 3722b52..8a76c0f 100644 --- a/game/src/GameSession/GameSessionMenu.gd +++ b/game/src/GameSession/GameSessionMenu.gd @@ -1,19 +1,24 @@ extends PanelContainer -signal close_button_pressed - @export var _main_menu_scene : PackedScene -func _ready(): - print("GameSessionMenu ready") +signal options_button_pressed # REQUIREMENTS: # * SS-47 # * UIFUN-69 -func _on_to_main_menu_pressed(): +func _on_main_menu_confirmed() -> void: get_tree().change_scene_to_packed(_main_menu_scene) # REQUIREMENTS: -# * UIFUN-69 -func _on_close_button_pressed(): - close_button_pressed.emit() +# * SS-48 +# * UIFUN-70 +func _on_quit_confirmed() -> void: + get_tree().quit() + +# REQUIREMENTS: +# * SS-7, SS-46 +# * UIFUN-11 +func _on_options_button_pressed() -> void: + hide() + options_button_pressed.emit() diff --git a/game/src/GameSession/GameSessionMenu.tscn b/game/src/GameSession/GameSessionMenu.tscn index 45fff4b..a753184 100644 --- a/game/src/GameSession/GameSessionMenu.tscn +++ b/game/src/GameSession/GameSessionMenu.tscn @@ -8,21 +8,64 @@ editor_description = "UI-68" script = ExtResource("1_usq6o") _main_menu_scene = ExtResource("2_xi6a4") -[node name="VBoxContainer" type="VBoxContainer" parent="."] +[node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 -[node name="MainMenuButton" type="Button" parent="VBoxContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="SaveButton" type="Button" parent="MarginContainer/VBoxContainer"] +editor_description = "UI-69" +layout_mode = 2 +text = "GAMESESSIONMENU_SAVE" + +[node name="LoadButton" type="Button" parent="MarginContainer/VBoxContainer"] +editor_description = "UI-70" +layout_mode = 2 +text = "GAMESESSIONMENU_LOAD" + +[node name="OptionsButton" type="Button" parent="MarginContainer/VBoxContainer"] +editor_description = "UI-10" +layout_mode = 2 +text = "GAMESESSIONMENU_OPTIONS" + +[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"] editor_description = "UI-71" layout_mode = 2 -text = "GAMESESSIONMENU_RESIGN" +text = "GAMESESSIONMENU_MAINMENU" + +[node name="QuitButton" type="Button" parent="MarginContainer/VBoxContainer"] +editor_description = "UI-72" +layout_mode = 2 +text = "GAMESESSIONMENU_QUIT" -[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"] layout_mode = 2 -[node name="CloseButton" type="Button" parent="VBoxContainer"] -editor_description = "UI-80" +[node name="CloseButton" type="Button" parent="MarginContainer/VBoxContainer"] +editor_description = "SS-64, UI-80, UIFUN-79" layout_mode = 2 text = "GAMESESSIONMENU_CLOSE" -[connection signal="pressed" from="VBoxContainer/MainMenuButton" to="." method="_on_to_main_menu_pressed"] -[connection signal="pressed" from="VBoxContainer/CloseButton" to="." method="_on_close_button_pressed"] +[node name="MainMenuDialog" type="ConfirmationDialog" parent="."] +title = "GAMESESSIONMENU_MAINMENU_DIALOG_TITLE" +ok_button_text = "DIALOG_OK" +dialog_text = "GAMESESSIONMENU_MAINMENU_DIALOG_TEXT" +cancel_button_text = "DIALOG_CANCEL" + +[node name="QuitDialog" type="ConfirmationDialog" parent="."] +title = "GAMESESSIONMENU_QUIT_DIALOG_TITLE" +ok_button_text = "DIALOG_OK" +dialog_text = "GAMESESSIONMENU_QUIT_DIALOG_TEXT" +cancel_button_text = "DIALOG_CANCEL" + +[connection signal="pressed" from="MarginContainer/VBoxContainer/OptionsButton" to="." method="_on_options_button_pressed"] +[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="MainMenuDialog" method="popup_centered"] +[connection signal="pressed" from="MarginContainer/VBoxContainer/QuitButton" to="QuitDialog" method="popup_centered"] +[connection signal="pressed" from="MarginContainer/VBoxContainer/CloseButton" to="." method="hide"] +[connection signal="confirmed" from="MainMenuDialog" to="." method="_on_main_menu_confirmed"] +[connection signal="confirmed" from="QuitDialog" to="." method="_on_quit_confirmed"] diff --git a/game/src/GameSession/MapControlPanel.gd b/game/src/GameSession/MapControlPanel.gd index 693890f..d5810c5 100644 --- a/game/src/GameSession/MapControlPanel.gd +++ b/game/src/GameSession/MapControlPanel.gd @@ -4,6 +4,8 @@ signal game_session_menu_button_pressed signal mapmode_changed signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) signal minimap_clicked(pos_clicked : Vector2) +signal zoom_in_button_pressed +signal zoom_out_button_pressed @export var _mapmodes_grid : GridContainer @@ -17,6 +19,7 @@ func _add_mapmode_button(identifier : String) -> void: button.tooltip_text = identifier button.toggle_mode = true button.button_group = _mapmode_button_group + button.mouse_filter = MOUSE_FILTER_PASS _mapmodes_grid.add_child(button) if _mapmode_button_group.get_pressed_button() == null: button.button_pressed = true @@ -44,3 +47,13 @@ func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_ri func _on_minimap_clicked(pos_clicked : Vector2) -> void: minimap_clicked.emit(pos_clicked) + +# REQUIREMENTS: +# * UIFUN-269 +func _on_zoom_in_button_pressed() -> void: + zoom_in_button_pressed.emit() + +# REQUIREMENTS: +# * UIFUN-270 +func _on_zoom_out_button_pressed() -> void: + zoom_out_button_pressed.emit() diff --git a/game/src/GameSession/MapControlPanel.tscn b/game/src/GameSession/MapControlPanel.tscn index 70d7eab..27205e3 100644 --- a/game/src/GameSession/MapControlPanel.tscn +++ b/game/src/GameSession/MapControlPanel.tscn @@ -15,49 +15,89 @@ events = [SubResource("InputEventAction_5nck3")] editor_description = "SS-103" mouse_filter = 1 script = ExtResource("1_ign64") -_mapmodes_grid = NodePath("HBoxContainer/VBoxContainer/MapmodesGrid") +_mapmodes_grid = NodePath("MarginContainer/HBoxContainer/VBoxContainer/MapmodesGrid") -[node name="HBoxContainer" type="HBoxContainer" parent="."] +[node name="MarginContainer" type="MarginContainer" parent="."] layout_mode = 2 -alignment = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 -[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] layout_mode = 2 +theme_override_constants/separation = 6 +alignment = 1 -[node name="MapmodesGrid" type="GridContainer" parent="HBoxContainer/VBoxContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="MapmodesGrid" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] editor_description = "UI-750" layout_mode = 2 columns = 11 -[node name="Minimap" type="PanelContainer" parent="HBoxContainer/VBoxContainer"] +[node name="Minimap" type="PanelContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] editor_description = "UI-549" layout_mode = 2 mouse_filter = 1 -[node name="TextureRect" type="TextureRect" parent="HBoxContainer/VBoxContainer/Minimap"] +[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] editor_description = "UI-751, FS-338" layout_mode = 2 texture = ExtResource("2_r613r") -[node name="ViewportQuad" type="Control" parent="HBoxContainer/VBoxContainer/Minimap"] +[node name="ViewportQuad" type="Control" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] layout_mode = 2 mouse_filter = 2 script = ExtResource("3_s4dml") -[node name="Frame" type="NinePatchRect" parent="HBoxContainer/VBoxContainer/Minimap"] +[node name="Frame" type="NinePatchRect" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] layout_mode = 2 texture = ExtResource("4_f1exl") -[node name="AuxiliaryPanel" type="VBoxContainer" parent="HBoxContainer"] +[node name="AuxiliaryPanel" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] editor_description = "UI-761" layout_mode = 2 -[node name="GameSessionMenuButton" type="Button" parent="HBoxContainer/AuxiliaryPanel"] +[node name="GameSessionMenuButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] editor_description = "UI-9" layout_mode = 2 +mouse_filter = 1 shortcut = SubResource("Shortcut_fc1tk") text = "ESC" -[connection signal="map_view_camera_changed" from="." to="HBoxContainer/VBoxContainer/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] -[connection signal="minimap_clicked" from="HBoxContainer/VBoxContainer/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] -[connection signal="pressed" from="HBoxContainer/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] +[node name="LedgerButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +editor_description = "UI-860" +layout_mode = 2 +mouse_filter = 1 +text = "L" + +[node name="FindButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +editor_description = "UI-861" +layout_mode = 2 +mouse_filter = 1 +text = "F" + +[node name="ZoomButtonsContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +layout_mode = 2 +alignment = 1 + +[node name="ZoomInButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer"] +editor_description = "UI-862" +layout_mode = 2 +mouse_filter = 1 +text = "+" + +[node name="ZoomOutButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer"] +editor_description = "UI-863" +layout_mode = 2 +mouse_filter = 1 +text = "-" + +[connection signal="map_view_camera_changed" from="." to="MarginContainer/HBoxContainer/VBoxContainer/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] +[connection signal="minimap_clicked" from="MarginContainer/HBoxContainer/VBoxContainer/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] +[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] +[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer/ZoomInButton" to="." method="_on_zoom_in_button_pressed"] +[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer/ZoomOutButton" to="." method="_on_zoom_out_button_pressed"] diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index 54d8df8..ae49e82 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -16,6 +16,7 @@ const _shader_param_province_index : StringName = &"province_index_tex" const _shader_param_province_colour : StringName = &"province_colour_tex" const _shader_param_hover_index : StringName = &"hover_index" const _shader_param_selected_index : StringName = &"selected_index" +const _shader_param_terrain_tile_factor : StringName = &"terrain_tile_factor" @export var _camera : Camera3D @@ -25,9 +26,9 @@ const _shader_param_selected_index : StringName = &"selected_index" var _drag_anchor : Vector2 var _drag_active : bool = false -var _mouse_over_viewport : bool = false +var _mouse_over_viewport : bool = true -@export var _zoom_target_min : float = 0.2 +@export var _zoom_target_min : float = 0.05 @export var _zoom_target_max : float = 5.0 @export var _zoom_target_step : float = 0.1 @export var _zoom_epsilon : float = _zoom_target_step * 0.1 @@ -100,6 +101,7 @@ func _ready(): # Set map mesh size and get bounds _map_image_size = Vector2(Vector2i(MapSingleton.get_width(), MapSingleton.get_height())) _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y + _map_shader_material.set_shader_parameter(_shader_param_terrain_tile_factor, _map_image_size.y / 64.0) var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform _map_mesh_corner = Vector2( min(map_mesh_aabb.position.x, map_mesh_aabb.end.x), @@ -137,10 +139,16 @@ func _viewport_to_map_coords(pos_viewport : Vector2) -> Vector2: push_error("Invalid intersection: ", intersection) return Vector2(0.5, 0.5) +func zoom_in() -> void: + _zoom_target -= _zoom_target_step + +func zoom_out() -> void: + _zoom_target += _zoom_target_step + # REQUIREMENTS # * SS-31 func _unhandled_input(event : InputEvent): - if event.is_action_pressed(_action_click): + if _mouse_over_viewport and event.is_action_pressed(_action_click): # Check if the mouse is outside of bounds if _map_mesh.is_valid_uv_coord(_mouse_pos_map): var selected_index := MapSingleton.get_province_index_from_uv_coords(_mouse_pos_map) @@ -159,9 +167,9 @@ func _unhandled_input(event : InputEvent): push_warning("Drag being deactivated while already not active!") _drag_active = false elif event.is_action_pressed(_action_zoomin, true): - _zoom_target -= _zoom_target_step + zoom_in() elif event.is_action_pressed(_action_zoomout, true): - _zoom_target += _zoom_target_step + zoom_out() func _physics_process(delta : float): _mouse_pos_viewport = get_viewport().get_mouse_position() @@ -228,7 +236,7 @@ func _zoom_process(delta : float) -> void: _camera.position.y = height func _update_orientation() -> void: - var dir := Vector3(0, -1, -exp(-_camera.position.y * 2.0 + 0.5)) + var dir := Vector3(0, -1, -exp(-_camera.position.y - 1)) _camera.look_at(_camera.position + dir) func _update_minimap_viewport() -> void: @@ -254,4 +262,12 @@ func _on_minimap_clicked(pos_clicked : Vector2): pos_clicked *= _map_mesh_dims _camera.position.x = pos_clicked.x _camera.position.z = pos_clicked.y - _clamp_over_map() \ No newline at end of file + _clamp_over_map() + +func enable_processing() -> void: + set_process_unhandled_input(true) + set_physics_process(true) + +func disable_processing() -> void: + set_process_unhandled_input(false) + set_physics_process(false) diff --git a/game/src/GameSession/MapView.tscn b/game/src/GameSession/MapView.tscn index 93fc162..c8934c5 100644 --- a/game/src/GameSession/MapView.tscn +++ b/game/src/GameSession/MapView.tscn @@ -2,14 +2,15 @@ [ext_resource type="Script" path="res://src/GameSession/MapView.gd" id="1_exccw"] [ext_resource type="Shader" path="res://src/GameSession/TerrainMap.gdshader" id="1_upocn"] -[ext_resource type="Texture2D" uid="uid://cmw0pvjthnn8c" path="res://art/terrain/terrain.png" id="3_l8pnf"] +[ext_resource type="Texture2D" uid="uid://ckf222w5usrsu" path="res://art/terrain/farmlands.png" id="3_47mq1"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_tayeg"] render_priority = 0 shader = ExtResource("1_upocn") shader_parameter/hover_index = null shader_parameter/selected_index = null -shader_parameter/terrain_tex = ExtResource("3_l8pnf") +shader_parameter/terrain_tile_factor = null +shader_parameter/farmlands_tex = ExtResource("3_47mq1") [sub_resource type="MapMesh" id="MapMesh_3gtsd"] @@ -21,6 +22,7 @@ _map_mesh_instance = NodePath("MapMeshInstance") [node name="MapCamera" type="Camera3D" parent="."] transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0.25, 1.5, -2.75) +near = 0.01 [node name="MapMeshInstance" type="MeshInstance3D" parent="."] editor_description = "FS-343" diff --git a/game/src/GameSession/ProvinceOverviewPanel.gd b/game/src/GameSession/ProvinceOverviewPanel.gd index 434f6b1..4615df9 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.gd +++ b/game/src/GameSession/ProvinceOverviewPanel.gd @@ -1,22 +1,33 @@ extends Panel @export var _province_name_label : Label +@export var _region_name_label : Label -@export var province_identifier: String = "": - get: return province_identifier +var _province_identifier: String = "": + get: return _province_identifier set(v): - province_identifier = v + _province_identifier = v update_info() +const _name_suffix : String = "_NAME" + func _ready(): update_info() func update_info() -> void: - _province_name_label.text = province_identifier + "_NAME" - visible = not province_identifier.is_empty() + if _province_identifier: + _province_name_label.text = _province_identifier + _name_suffix + var region_identifier := MapSingleton.get_region_identifier_from_province_identifier(_province_identifier) + if region_identifier: + _region_name_label.text = region_identifier + _name_suffix + else: + _region_name_label.text = "NO REGION" + show() + else: + hide() func _on_province_selected(identifier : String) -> void: - province_identifier = identifier + _province_identifier = identifier -func _on_button_pressed() -> void: - province_identifier = "" +func _on_close_button_pressed() -> void: + _province_identifier = "" diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn index 2df95fb..7d21edc 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.tscn +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] -[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label")] +[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label", "_region_name_label")] editor_description = "UI-56" anchors_preset = 2 anchor_top = 1.0 @@ -12,6 +12,7 @@ offset_right = 200.0 grow_vertical = 0 script = ExtResource("1_3n8k5") _province_name_label = NodePath("VBoxContainer/ProvinceName") +_region_name_label = NodePath("VBoxContainer/RegionName") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -29,7 +30,13 @@ layout_mode = 2 text = "PROVINCE_NAME" vertical_alignment = 1 -[node name="Button" type="Button" parent="."] +[node name="RegionName" type="Label" parent="VBoxContainer"] +editor_description = "UI-58" +layout_mode = 2 +text = "REGION_NAME" +vertical_alignment = 1 + +[node name="CloseButton" type="Button" parent="."] custom_minimum_size = Vector2(30, 30) layout_mode = 1 anchors_preset = -1 @@ -39,4 +46,4 @@ anchor_bottom = 0.103333 grow_horizontal = 0 text = "X" -[connection signal="pressed" from="Button" to="." method="_on_button_pressed"] +[connection signal="pressed" from="CloseButton" to="." method="_on_close_button_pressed"] diff --git a/game/src/GameSession/TerrainMap.gdshader b/game/src/GameSession/TerrainMap.gdshader index 7aca0f9..9ce1a24 100644 --- a/game/src/GameSession/TerrainMap.gdshader +++ b/game/src/GameSession/TerrainMap.gdshader @@ -2,16 +2,18 @@ shader_type spatial; render_mode unshaded; -// Cosmetic terrain texture -uniform sampler2D terrain_tex: source_color, repeat_enable, filter_linear; +// Cosmetic farmlands terrain texture +uniform sampler2D farmlands_tex: source_color, repeat_enable, filter_linear; // Province index texture -uniform sampler2D province_index_tex : repeat_enable, filter_nearest; +uniform sampler2D province_index_tex : source_color, repeat_enable, filter_nearest; // Province colour texture uniform sampler2D province_colour_tex: source_color, repeat_enable, filter_nearest; // Index of the mouse over the map mesh uniform uint hover_index; // Index of the currently selected province uniform uint selected_index; +// The number of times the terrain textures should tile vertically +uniform float terrain_tile_factor; uvec2 vec2_to_uvec2(vec2 v) { return uvec2(v * 255.0); @@ -29,17 +31,39 @@ uint read_uint16(sampler2D tex, vec2 uv) { return uvec2_to_uint(read_uvec2(tex, uv)); } -void fragment() { - uvec2 prov_idx_split = read_uvec2(province_index_tex, UV); - uint prov_index = uvec2_to_uint(prov_idx_split); +const vec3 water_colour = vec3(0, 0, 1); + +vec3 get_terrain_colour(vec2 uv, vec2 corner, vec2 half_pixel_size, vec2 terrain_uv) { + uvec2 index_split = read_uvec2(province_index_tex, fma(corner, half_pixel_size, uv)); + uint index = uvec2_to_uint(index_split); + vec4 province_data = texelFetch(province_colour_tex, ivec2(index_split), 0); + vec3 province_colour = province_data.rgb; + float is_land = province_data.a; + vec3 farmlands_colour = texture(farmlands_tex, terrain_uv).rgb; + vec3 terrain_colour = mix(water_colour, farmlands_colour, is_land); + float mix_val = 0.4 + float(index == hover_index) * 0.2 + float(index == selected_index) * 0.2; + vec3 mixed_colour = mix(terrain_colour, province_colour, mix_val); + return mixed_colour; +} - // Boost prov_colour's contribution if it matches hover_colour or selected_colour - float mix_val = 0.3 + float(prov_index == hover_index) * 0.3 + float(prov_index == selected_index) * 0.3; - // Don't mix if the province index is 0 - mix_val *= float(prov_index != 0u); +vec3 mix_terrain_colour(vec2 uv) { + vec2 map_size = vec2(textureSize(province_index_tex, 0)); + vec2 pixel_offset = mod(fma(uv, map_size, vec2(0.5)), 1.0); + vec2 half_pixel_size = 0.49 / map_size; - vec3 terrain_colour = texture(terrain_tex, UV).rgb; - vec3 province_colour = texelFetch(province_colour_tex, ivec2(prov_idx_split), 0).rgb; + vec2 terrain_uv = uv; + terrain_uv.x *= map_size.x / map_size.y; + terrain_uv *= terrain_tile_factor; - ALBEDO = mix(terrain_colour, province_colour, mix_val); + return mix( + mix(get_terrain_colour(uv, vec2(-1, -1), half_pixel_size, terrain_uv), + get_terrain_colour(uv, vec2(+1, -1), half_pixel_size, terrain_uv), pixel_offset.x), + mix(get_terrain_colour(uv, vec2(-1, +1), half_pixel_size, terrain_uv), + get_terrain_colour(uv, vec2(+1, +1), half_pixel_size, terrain_uv), pixel_offset.x), + pixel_offset.y); +} + +void fragment() { + vec3 terrain_colour = mix_terrain_colour(UV); + ALBEDO = terrain_colour; } -- cgit v1.2.3-56-ga3b1 From c945680d960ccd0fb4a0ef5058ddfdd48e150f2d Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Mon, 17 Apr 2023 21:03:02 -0400 Subject: Added game speed panel to GameSession --- game/src/GameSession/GameSession.tscn | 6 ++++- game/src/GameSession/GameSpeedPanel.gd | 33 +++++++++++++++++++++++++++ game/src/GameSession/GameSpeedPanel.tscn | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 game/src/GameSession/GameSpeedPanel.gd create mode 100644 game/src/GameSession/GameSpeedPanel.tscn diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index d23cb6c..864c657 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=7 format=3 uid="uid://bgnupcshe1m7r"] +[gd_scene load_steps=8 format=3 uid="uid://bgnupcshe1m7r"] [ext_resource type="Script" path="res://src/GameSession/GameSession.gd" id="1_eklvp"] [ext_resource type="PackedScene" uid="uid://g524p8lr574w" path="res://src/GameSession/MapControlPanel.tscn" id="3_afh6d"] @@ -6,6 +6,7 @@ [ext_resource type="PackedScene" uid="uid://dkehmdnuxih2r" path="res://src/GameSession/MapView.tscn" id="4_xkg5j"] [ext_resource type="PackedScene" uid="uid://byq323jbel48u" path="res://src/GameSession/ProvinceOverviewPanel.tscn" id="5_osjnn"] [ext_resource type="PackedScene" uid="uid://cnbfxjy1m6wja" path="res://src/OptionMenu/OptionsMenu.tscn" id="6_p5mnx"] +[ext_resource type="PackedScene" uid="uid://dd8k3p7r3huwc" path="res://src/GameSession/GameSpeedPanel.tscn" id="7_myy4q"] [node name="GameSession" type="Control" node_paths=PackedStringArray("_game_session_menu")] editor_description = "SS-102, UI-546" @@ -49,6 +50,9 @@ layout_mode = 1 visible = false layout_mode = 1 +[node name="GameSpeedPanel" parent="." instance=ExtResource("7_myy4q")] +layout_mode = 0 + [connection signal="map_view_camera_changed" from="MapView" to="MapControlPanel" method="_on_map_view_camera_changed"] [connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] [connection signal="options_button_pressed" from="GameSessionMenu" to="OptionsMenu" method="show"] diff --git a/game/src/GameSession/GameSpeedPanel.gd b/game/src/GameSession/GameSpeedPanel.gd new file mode 100644 index 0000000..8dc35d7 --- /dev/null +++ b/game/src/GameSession/GameSpeedPanel.gd @@ -0,0 +1,33 @@ +extends PanelContainer + +#UI-74 UI-75 UI-76 UI-77 + +@export var _longform_date_button : Button +@export var _play_pause_display_button : Button +@export var _decrease_speed_button : Button +@export var _increase_speed_button : Button + +var is_game_paused : bool = true + +# Called when the node enters the scene tree for the first time. +func _ready(): + _update_playpause_button() + +func _update_playpause_button(): + _play_pause_display_button.text = "⏸️" if is_game_paused else "▶" + print("Game is paused" if is_game_paused else "Game is advancing") + + +func _on_decrease_speed_button_pressed(): + print("Decrease speed") + +func _on_increase_speed_button_pressed(): + print("Increase speed") + +func _on_play_pause_display_button_pressed(): + is_game_paused = !is_game_paused + _update_playpause_button() + +func _on_longform_date_label_pressed(): + is_game_paused = !is_game_paused + _update_playpause_button() diff --git a/game/src/GameSession/GameSpeedPanel.tscn b/game/src/GameSession/GameSpeedPanel.tscn new file mode 100644 index 0000000..bfb869c --- /dev/null +++ b/game/src/GameSession/GameSpeedPanel.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=2 format=3 uid="uid://dd8k3p7r3huwc"] + +[ext_resource type="Script" path="res://src/GameSession/GameSpeedPanel.gd" id="1_pfs8t"] + +[node name="GameSpeedPanel" type="PanelContainer" node_paths=PackedStringArray("_longform_date_button", "_play_pause_display_button", "_decrease_speed_button", "_increase_speed_button")] +script = ExtResource("1_pfs8t") +_longform_date_button = NodePath("HBoxContainer/LongformDateButton") +_play_pause_display_button = NodePath("HBoxContainer/PlayPauseDisplayButton") +_decrease_speed_button = NodePath("HBoxContainer/DecreaseSpeedButton") +_increase_speed_button = NodePath("HBoxContainer/IncreaseSpeedButton") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="LongformDateButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 +text = "LONGFORM DATE" + +[node name="PlayPauseDisplayButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "⏸" + +[node name="DecreaseSpeedButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "➖" + +[node name="IncreaseSpeedButton" type="Button" parent="HBoxContainer"] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "➕" + +[connection signal="pressed" from="HBoxContainer/LongformDateButton" to="." method="_on_longform_date_label_pressed"] +[connection signal="pressed" from="HBoxContainer/PlayPauseDisplayButton" to="." method="_on_play_pause_display_button_pressed"] +[connection signal="pressed" from="HBoxContainer/DecreaseSpeedButton" to="." method="_on_decrease_speed_button_pressed"] +[connection signal="pressed" from="HBoxContainer/IncreaseSpeedButton" to="." method="_on_increase_speed_button_pressed"] -- cgit v1.2.3-56-ga3b1 From 18151dc9829701a20d0bc12e83958ddfe9beb039 Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Mon, 17 Apr 2023 21:08:25 -0400 Subject: Added music player control to GameSession --- game/src/GameSession/GameSession.tscn | 12 +++++++++++- game/src/MusicConductor/MusicPlayer.gd | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index 864c657..8a8b18c 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=8 format=3 uid="uid://bgnupcshe1m7r"] +[gd_scene load_steps=9 format=3 uid="uid://bgnupcshe1m7r"] [ext_resource type="Script" path="res://src/GameSession/GameSession.gd" id="1_eklvp"] +[ext_resource type="PackedScene" uid="uid://cvl76duuym1wq" path="res://src/MusicConductor/MusicPlayer.tscn" id="2_kt6aa"] [ext_resource type="PackedScene" uid="uid://g524p8lr574w" path="res://src/GameSession/MapControlPanel.tscn" id="3_afh6d"] [ext_resource type="PackedScene" uid="uid://dvdynl6eir40o" path="res://src/GameSession/GameSessionMenu.tscn" id="3_bvmqh"] [ext_resource type="PackedScene" uid="uid://dkehmdnuxih2r" path="res://src/GameSession/MapView.tscn" id="4_xkg5j"] @@ -20,6 +21,15 @@ mouse_filter = 2 script = ExtResource("1_eklvp") _game_session_menu = NodePath("GameSessionMenu") +[node name="MusicPlayer" parent="." instance=ExtResource("2_kt6aa")] +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -150.0 +offset_bottom = 110.0 +grow_horizontal = 0 + [node name="MapView" parent="." instance=ExtResource("4_xkg5j")] [node name="GameSessionMenu" parent="." instance=ExtResource("3_bvmqh")] diff --git a/game/src/MusicConductor/MusicPlayer.gd b/game/src/MusicConductor/MusicPlayer.gd index baf8a43..b775b84 100644 --- a/game/src/MusicConductor/MusicPlayer.gd +++ b/game/src/MusicConductor/MusicPlayer.gd @@ -44,6 +44,8 @@ func _on_previous_song_button_pressed(): func _on_option_button_item_selected(index): # UIFUN-92 MusicConductor.start_song_by_index(index) + _update_song_name_visual() + _update_play_pause_button() func _on_progress_slider_drag_started(): -- cgit v1.2.3-56-ga3b1 From 0ead900c96f1f40028d53b0e4b9c2d93312a6621 Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Mon, 17 Apr 2023 22:25:09 -0400 Subject: Double-click a start date to automatically start a game session --- game/src/LobbyMenu/LobbyMenu.gd | 5 +++++ game/src/LobbyMenu/LobbyMenu.tscn | 1 + 2 files changed, 6 insertions(+) diff --git a/game/src/LobbyMenu/LobbyMenu.gd b/game/src/LobbyMenu/LobbyMenu.gd index 802dac3..4fc06c9 100644 --- a/game/src/LobbyMenu/LobbyMenu.gd +++ b/game/src/LobbyMenu/LobbyMenu.gd @@ -34,3 +34,8 @@ func _on_game_select_list_item_selected(index): func _on_save_game_selected(_index): start_button.disabled = false + +# If the date is double-clicked, start the game! +func _on_game_select_list_item_activated(index): + _on_game_select_list_item_selected(index) + _on_start_button_button_down() diff --git a/game/src/LobbyMenu/LobbyMenu.tscn b/game/src/LobbyMenu/LobbyMenu.tscn index 528e7ae..174fb72 100644 --- a/game/src/LobbyMenu/LobbyMenu.tscn +++ b/game/src/LobbyMenu/LobbyMenu.tscn @@ -78,6 +78,7 @@ custom_minimum_size = Vector2(0, 33) layout_mode = 2 [connection signal="save_game_selected" from="." to="." method="_on_save_game_selected"] +[connection signal="item_activated" from="GameSelectPanel/VBoxContainer/GameSelectList" to="." method="_on_game_select_list_item_activated"] [connection signal="item_selected" from="GameSelectPanel/VBoxContainer/GameSelectList" to="." method="_on_game_select_list_item_selected"] [connection signal="button_down" from="GameSelectPanel/VBoxContainer/BackButton" to="." method="_on_back_button_button_down"] [connection signal="button_down" from="GameStartPanel/VBoxContainer/StartButton" to="." method="_on_start_button_button_down"] -- cgit v1.2.3-56-ga3b1 From 1084a5d64df5d3465ef90b3b85fe3374636a3fe8 Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Thu, 20 Apr 2023 00:00:38 -0400 Subject: Added basic outlines of Canadian provinces + territories --- game/common/map/provinces.json | 17 ++++++++++++++++- game/common/map/provinces.png | Bin 1083451 -> 1105620 bytes game/common/map/regions.json | 2 +- game/localisation/en_GB/provinces.csv | 17 ++++++++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/game/common/map/provinces.json b/game/common/map/provinces.json index 71be5cb..637a687 100644 --- a/game/common/map/provinces.json +++ b/game/common/map/provinces.json @@ -47,8 +47,23 @@ "prov_russia": "006311", "prov_north_america": "A114FF", + + "prov_victoria": "59FF93", + "prov_calgary": "EA00C7", + "prov_saskatoon": "4F8E0F", + "prov_winnipeg": "EA4F12", + "prov_ottawa": "FF0000", + "prov_quebec": "6430AD", + "prov_new_brunswick": "53AF3B", + "prov_prince_edward_island": "BF4E11", + "prov_nova_scotia": "BC0F34", + "prov_labrador": "FF2D5E", + "prov_newfoundland": "1115FF", + "prov_whitehorse": "256B2D", + "prov_yellowknife": "A0133B", + "prov_iqaluit": "C1AE00", + "prov_cuba": "1E29FF", - "prov_nova_scotia": "1115FF", "prov_bermuda": "FF2370", "prov_jamaica": "329600", "prov_hispaniola": "742B7C", diff --git a/game/common/map/provinces.png b/game/common/map/provinces.png index 73cc33c..be5b52e 100644 Binary files a/game/common/map/provinces.png and b/game/common/map/provinces.png differ diff --git a/game/common/map/regions.json b/game/common/map/regions.json index 1684fb5..5bb67e2 100644 --- a/game/common/map/regions.json +++ b/game/common/map/regions.json @@ -1,7 +1,7 @@ { "region_europe": ["prov_britain", "prov_ireland", "prov_iceland", "prov_corsica", "prov_sardinia", "prov_sicily", "prov_malta", "prov_cyprus", "prov_greenland", "prov_baleares", "prov_gotland", "prov_crete", "prov_jan_mayen", "prov_faroes", "prov_mann", "prov_shetlands", "prov_orkney", "prov_channel_islands", "prov_madiera", "prov_canarias", "prov_sjaeland", "prov_bornholm", "prov_bear_island", "prov_pantelleria", "prov_iberia", "prov_scandinavia", "prov_jutland", "prov_fyn", "prov_hiiumaa", "prov_saaremaa", "prov_italy", "prov_elba", "prov_france", "prov_netherlands", "prov_belgium", "prov_luxembourg", "prov_switzerland", "prov_balkans", "prov_crimea", "prov_germany", "prov_poland", "prov_baltics", "prov_finland", "prov_aland", "prov_ukraine", "prov_russia"], - "region_north_america": ["prov_north_america", "prov_cuba", "prov_nova_scotia", "prov_bermuda", "prov_jamaica", "prov_hispaniola", "prov_aleutians", "prov_bahamas", "prov_turks_and_caicos", "prov_puerto_rico", "prov_barbados", "prov_grenada", "prov_st_vincent", "prov_st_lucia", "prov_martinique", "prov_dominica", "prov_guadeloupe", "prov_montserrat", "prov_antigua", "prov_barbuda", "prov_st_kitts", "prov_west_virgin_islands", "prov_east_virgin_islands", "prov_cayman_islands", "prov_angulia", "prov_central_america", "prov_mexico"], + "region_north_america": ["prov_north_america", "prov_cuba", "prov_bermuda", "prov_jamaica", "prov_hispaniola", "prov_aleutians", "prov_bahamas", "prov_turks_and_caicos", "prov_puerto_rico", "prov_barbados", "prov_grenada", "prov_st_vincent", "prov_st_lucia", "prov_martinique", "prov_dominica", "prov_guadeloupe", "prov_montserrat", "prov_antigua", "prov_barbuda", "prov_st_kitts", "prov_west_virgin_islands", "prov_east_virgin_islands", "prov_cayman_islands", "prov_angulia", "prov_central_america", "prov_mexico", "prov_victoria", "prov_calgary", "prov_saskatoon", "prov_winnipeg", "prov_ottawa", "prov_quebec", "prov_new_brunswick", "prov_prince_edward_island", "prov_nova_scotia", "prov_labrador", "prov_newfoundland", "prov_whitehorse", "prov_yellowknife", "prov_iqaluit"], "region_south_america": ["prov_south_america", "prov_galapagos", "prov_falklands", "prov_south_georgia"], diff --git a/game/localisation/en_GB/provinces.csv b/game/localisation/en_GB/provinces.csv index 24248a0..814b4f9 100644 --- a/game/localisation/en_GB/provinces.csv +++ b/game/localisation/en_GB/provinces.csv @@ -50,7 +50,6 @@ prov_russia_NAME,Russia ,, North America prov_north_america_NAME,North America prov_cuba_NAME,Cuba -prov_nova_scotia_NAME,Nova Scotia prov_bermuda_NAME,Bermuda prov_jamaica_NAME,Jamaica prov_hispaniola_NAME,Hispaniola @@ -76,6 +75,22 @@ prov_angulia_NAME,Angulia prov_central_america_NAME,Central America prov_mexico_NAME,Mexico +,, Canada +prov_victoria_NAME,Victoria +prov_calgary_NAME,Calgary +prov_saskatoon_NAME,Saskatoon +prov_winnipeg_NAME,Winnipeg +prov_ottawa_NAME,Ottawa +prov_quebec_NAME,Quebec +prov_new_brunswick_NAME,New Brunswick +prov_prince_edward_island_NAME,Prince Edward Island +prov_nova_scotia_NAME,Nova Scotia +prov_labrador_NAME,Labrador +prov_newfoundland_NAME,Newfoundland +prov_whitehorse_NAME,Whitehorse +prov_yellowknife_NAME,Yellowknife +prov_iqaluit_NAME,Iqaluit + ,, South America prov_south_america_NAME,South America prov_galapagos_NAME,Galapagos -- cgit v1.2.3-56-ga3b1 From 0e631cd4f2fa6304f91e0214844d2064d8e394c1 Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Sun, 23 Apr 2023 14:43:14 -0400 Subject: Added a .clang-format for formatting use --- .clang-format | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..fff079a --- /dev/null +++ b/.clang-format @@ -0,0 +1,48 @@ +--- +UseCRLF: false +Standard: c++20 +UseTab: Always +TabWidth: 4 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpacesInLineCommentPrefix: + Minimum: 1 +SpacesInContainerLiterals: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInAngles: Never +SpaceInEmptyParentheses: false +SpaceInEmptyBlock: false +SpaceBeforeSquareBrackets: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterFunctionDeclarationName: false + BeforeNonEmptyParentheses: false +SpaceBeforeParens: ControlStatements +SpaceBeforeInheritanceColon: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCaseColon: false +SpaceBeforeAssignmentOperators: true +SpaceAroundPointerQualifiers: Before +SpaceAfterTemplateKeyword: false +SpaceAfterLogicalNot: false +RemoveBracesLLVM: false +ReferenceAlignment: Left +PointerAlignment: Left +NamespaceIndentation: All +LineEnding: LF +Language: Cpp +InsertNewlineAtEOF: true +IndentExternBlock: Indent +IndentCaseLabels: true +FixNamespaceComments: false +Cpp11BracedListStyle: false +CompactNamespaces: false +BreakBeforeBraces: Attach +AlwaysBreakTemplateDeclarations: Yes +AlignTrailingComments: + Kind: Always +AlignEscapedNewlines: Left +AlignArrayOfStructures: Right -- cgit v1.2.3-56-ga3b1 From d3f3187209cb4085f27f95ce8ad2a77af25704fd Mon Sep 17 00:00:00 2001 From: Hop311 Date: Sun, 23 Apr 2023 19:49:01 +0100 Subject: C++ refactoring + simulation prototype --- .github/workflows/builds.yml | 4 + SConstruct | 6 + extension/src/GameSingleton.cpp | 449 ++++++++++++++++++++++++ extension/src/GameSingleton.hpp | 62 ++++ extension/src/MapSingleton.cpp | 394 --------------------- extension/src/MapSingleton.hpp | 50 --- extension/src/openvic2/Date.cpp | 190 ++++++---- extension/src/openvic2/Date.hpp | 139 ++++---- extension/src/openvic2/GameAdvancementHook.cpp | 120 ++++--- extension/src/openvic2/GameAdvancementHook.hpp | 29 +- extension/src/openvic2/GameManager.cpp | 43 +++ extension/src/openvic2/GameManager.hpp | 29 ++ extension/src/openvic2/Logger.cpp | 26 ++ extension/src/openvic2/Logger.hpp | 83 +++++ extension/src/openvic2/Map.cpp | 348 ------------------ extension/src/openvic2/Map.hpp | 67 ---- extension/src/openvic2/Province.cpp | 43 --- extension/src/openvic2/Province.hpp | 39 -- extension/src/openvic2/Region.cpp | 26 -- extension/src/openvic2/Region.hpp | 29 -- extension/src/openvic2/Types.cpp | 4 +- extension/src/openvic2/Types.hpp | 8 +- extension/src/openvic2/map/Building.cpp | 129 +++++++ extension/src/openvic2/map/Building.hpp | 63 ++++ extension/src/openvic2/map/Map.cpp | 359 +++++++++++++++++++ extension/src/openvic2/map/Map.hpp | 73 ++++ extension/src/openvic2/map/Province.cpp | 67 ++++ extension/src/openvic2/map/Province.hpp | 45 +++ extension/src/openvic2/map/Region.cpp | 26 ++ extension/src/openvic2/map/Region.hpp | 28 ++ extension/src/register_types.cpp | 14 +- game/localisation/en_GB/menus.csv | 9 + game/localisation/en_GB/provinces.csv | 374 ++++++++++---------- game/localisation/en_GB/regions.csv | 12 +- game/src/Autoload/Events.gd | 9 +- game/src/GameSession/GameSession.gd | 5 +- game/src/GameSession/GameSessionMenu.gd | 1 + game/src/GameSession/GameSpeedPanel.gd | 29 +- game/src/GameSession/MapControlPanel.gd | 6 +- game/src/GameSession/MapView.gd | 21 +- game/src/GameSession/ProvinceOverviewPanel.gd | 82 ++++- game/src/GameSession/ProvinceOverviewPanel.tscn | 14 +- 42 files changed, 2086 insertions(+), 1468 deletions(-) create mode 100644 extension/src/GameSingleton.cpp create mode 100644 extension/src/GameSingleton.hpp delete mode 100644 extension/src/MapSingleton.cpp delete mode 100644 extension/src/MapSingleton.hpp create mode 100644 extension/src/openvic2/GameManager.cpp create mode 100644 extension/src/openvic2/GameManager.hpp create mode 100644 extension/src/openvic2/Logger.cpp create mode 100644 extension/src/openvic2/Logger.hpp delete mode 100644 extension/src/openvic2/Map.cpp delete mode 100644 extension/src/openvic2/Map.hpp delete mode 100644 extension/src/openvic2/Province.cpp delete mode 100644 extension/src/openvic2/Province.hpp delete mode 100644 extension/src/openvic2/Region.cpp delete mode 100644 extension/src/openvic2/Region.hpp create mode 100644 extension/src/openvic2/map/Building.cpp create mode 100644 extension/src/openvic2/map/Building.hpp create mode 100644 extension/src/openvic2/map/Map.cpp create mode 100644 extension/src/openvic2/map/Map.hpp create mode 100644 extension/src/openvic2/map/Province.cpp create mode 100644 extension/src/openvic2/map/Province.hpp create mode 100644 extension/src/openvic2/map/Region.cpp create mode 100644 extension/src/openvic2/map/Region.hpp diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 772b16c..664f8e4 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -80,6 +80,10 @@ jobs: run: | sudo apt-get update -qq sudo apt-get install -qqq build-essential pkg-config + g++ --version + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12 + sudo update-alternatives --set g++ /usr/bin/g++-12 + g++ --version - name: Setup MinGW for Windows/MinGW build if: ${{ matrix.platform == 'windows' }} diff --git a/SConstruct b/SConstruct index 4e6fe70..3213efd 100644 --- a/SConstruct +++ b/SConstruct @@ -10,6 +10,12 @@ ARGUMENTS.pop('intermediate_delete', True) env = SConscript("godot-cpp/SConstruct") +# Require C++20 +if env.get("is_msvc", False): + env.Replace(CXXFLAGS=["/std:c++20"]) +else: + env.Replace(CXXFLAGS=["-std=c++20"]) + ARGUMENTS = SAVED_ARGUMENTS # Custom options and profile flags. diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp new file mode 100644 index 0000000..68eb252 --- /dev/null +++ b/extension/src/GameSingleton.cpp @@ -0,0 +1,449 @@ +#include "GameSingleton.hpp" + +#include +#include +#include + +#include "openvic2/Logger.hpp" + +using namespace godot; +using namespace OpenVic2; + +#define ERR(x) ((x) == SUCCESS ? OK : FAILED) + +GameSingleton* GameSingleton::singleton = nullptr; + +void GameSingleton::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &GameSingleton::load_province_identifier_file); + ClassDB::bind_method(D_METHOD("load_water_province_file", "file_path"), &GameSingleton::load_water_province_file); + ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &GameSingleton::load_region_file); + ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &GameSingleton::load_province_shape_file); + ClassDB::bind_method(D_METHOD("finished_loading_data"), &GameSingleton::finished_loading_data); + + ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &GameSingleton::get_province_index_from_uv_coords); + ClassDB::bind_method(D_METHOD("get_province_info_from_index", "index"), &GameSingleton::get_province_info_from_index); + ClassDB::bind_method(D_METHOD("get_width"), &GameSingleton::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &GameSingleton::get_height); + ClassDB::bind_method(D_METHOD("get_province_index_image"), &GameSingleton::get_province_index_image); + ClassDB::bind_method(D_METHOD("get_province_colour_image"), &GameSingleton::get_province_colour_image); + + ClassDB::bind_method(D_METHOD("update_colour_image"), &GameSingleton::update_colour_image); + ClassDB::bind_method(D_METHOD("get_mapmode_count"), &GameSingleton::get_mapmode_count); + ClassDB::bind_method(D_METHOD("get_mapmode_identifier", "index"), &GameSingleton::get_mapmode_identifier); + ClassDB::bind_method(D_METHOD("set_mapmode", "identifier"), &GameSingleton::set_mapmode); + + ClassDB::bind_method(D_METHOD("expand_building", "province_index", "building_type_identifier"), &GameSingleton::expand_building); + + ClassDB::bind_method(D_METHOD("set_paused", "paused"), &GameSingleton::set_paused); + ClassDB::bind_method(D_METHOD("toggle_paused"), &GameSingleton::toggle_paused); + ClassDB::bind_method(D_METHOD("is_paused"), &GameSingleton::is_paused); + ClassDB::bind_method(D_METHOD("increase_speed"), &GameSingleton::increase_speed); + ClassDB::bind_method(D_METHOD("decrease_speed"), &GameSingleton::decrease_speed); + ClassDB::bind_method(D_METHOD("can_increase_speed"), &GameSingleton::can_increase_speed); + ClassDB::bind_method(D_METHOD("can_decrease_speed"), &GameSingleton::can_decrease_speed); + ClassDB::bind_method(D_METHOD("get_longform_date"), &GameSingleton::get_longform_date); + ClassDB::bind_method(D_METHOD("try_tick"), &GameSingleton::try_tick); + + ADD_SIGNAL(MethodInfo("state_updated")); +} + +GameSingleton* GameSingleton::get_singleton() { + return singleton; +} + +/* REQUIREMENTS: + * MAP-21, MAP-25 + */ +GameSingleton::GameSingleton() : game_manager{ [this]() { emit_signal("state_updated"); } } { + ERR_FAIL_COND(singleton != nullptr); + singleton = this; + + Logger::set_info_func([](std::string&& str) { UtilityFunctions::print(str.c_str()); }); + Logger::set_error_func([](std::string&& str) { UtilityFunctions::push_error(str.c_str()); }); + + using mapmode_t = std::pair; + const std::vector mapmodes = { + { "mapmode_province", [](Map const&, Province const& province) -> Province::colour_t { return province.get_colour(); } }, + { "mapmode_region", [](Map const&, Province const& province) -> Province::colour_t { + Region const* region = province.get_region(); + if (region != nullptr) return region->get_colour(); + return province.get_colour(); + } }, + { "mapmode_terrain", [](Map const&, Province const& province) -> Province::colour_t { + return province.is_water() ? 0x4287F5 : 0x0D7017; + } }, + { "mapmode_index", [](Map const& map, Province const& province) -> Province::colour_t { + const uint8_t f = static_cast(province.get_index()) / static_cast(map.get_province_count()) * 255.0f; + return (f << 16) | (f << 8) | f; + } } + }; + for (mapmode_t const& mapmode : mapmodes) + game_manager.map.add_mapmode(mapmode.first, mapmode.second); + + using building_type_t = std::tuple; + const std::vector building_types = { + { "building_fort", 4, 8 }, { "building_naval_base", 6, 15 }, { "building_railroad", 5, 10 } + }; + for (building_type_t const& type : building_types) + game_manager.building_manager.add_building_type(std::get<0>(type), std::get<1>(type), std::get<2>(type)); + +} + +GameSingleton::~GameSingleton() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + +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 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(); + JSON json; + 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; + +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; +} + +Error GameSingleton::_parse_province_identifier_entry(String const& identifier, Variant const& entry) { + const Variant::Type type = entry.get_type(); + Province::colour_t colour = Province::NULL_COLOUR; + if (type == Variant::ARRAY) { + Array const& colour_array = entry; + if (colour_array.size() == 3) { + for (int jdx = 0; jdx < 3; ++jdx) { + Variant const& var = colour_array[jdx]; + if (var.get_type() != Variant::FLOAT) { + colour = Province::NULL_COLOUR; + break; + } + const double colour_double = var; + if (std::trunc(colour_double) != colour_double) { + colour = Province::NULL_COLOUR; + break; + } + const int64_t colour_int = static_cast(colour_double); + if (colour_int < 0 || colour_int > 255) { + colour = Province::NULL_COLOUR; + break; + } + colour = (colour << 8) | colour_int; + } + } + } else if (type == Variant::STRING) { + String const& colour_string = entry; + if (colour_string.is_valid_hex_number()) { + const int64_t colour_int = colour_string.hex_to_int(); + if (0 <= colour_int && colour_int <= 0xFFFFFF) + colour = colour_int; + } + } + if (colour == Province::NULL_COLOUR) { + UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry); + return FAILED; + } + return ERR(game_manager.map.add_province(identifier.utf8().get_data(), 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::_parse_region_entry(String const& identifier, Variant const& entry) { + Error err = OK; + Variant::Type type = entry.get_type(); + std::vector 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(province_string.utf8().get_data()); + } 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; + } + return ERR(game_manager.map.add_region(identifier.utf8().get_data(), province_identifiers)); +} + +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::load_province_shape_file(String const& file_path) { + if (province_index_image.is_valid()) { + UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); + return FAILED; + } + Ref province_shape_image; + province_shape_image.instantiate(); + Error err = province_shape_image->load(file_path); + if (err != OK) { + UtilityFunctions::push_error("Failed to load province shape file: ", file_path); + return err; + } + int32_t width = province_shape_image->get_width(); + int32_t height = province_shape_image->get_height(); + if (width < 1 || height < 1) { + UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); + err = FAILED; + } + static constexpr Image::Format expected_format = Image::FORMAT_RGB8; + const Image::Format format = province_shape_image->get_format(); + if (format != expected_format) { + UtilityFunctions::push_error("Invalid format (", format, ", should be ", expected_format, ") for province shape file: ", file_path); + err = FAILED; + } + if (err != OK) return err; + err = ERR(game_manager.map.generate_province_index_image(width, height, province_shape_image->get_data().ptr())); + + PackedByteArray index_data_array; + index_data_array.resize(width * height * sizeof(Province::index_t)); + std::vector const& province_index_data = game_manager.map.get_province_index_image(); + memcpy(index_data_array.ptrw(), province_index_data.data(), province_index_data.size()); + + province_index_image = Image::create_from_data(width, height, false, Image::FORMAT_RG8, index_data_array); + if (province_index_image.is_null()) { + UtilityFunctions::push_error("Failed to create province ID image"); + err = FAILED; + } + + if (update_colour_image() != OK) err = FAILED; + + return err; +} + +void GameSingleton::finished_loading_data() { + game_manager.finished_loading_data(); +} + +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(identifier.utf8().get_data()) != SUCCESS) + err = FAILED; + } + } + game_manager.map.lock_water_provinces(); + return err; +} + +int32_t GameSingleton::get_province_index_from_uv_coords(Vector2 const& coords) const { + const size_t x_mod_w = UtilityFunctions::fposmod(coords.x, 1.0f) * get_width(); + const size_t y_mod_h = UtilityFunctions::fposmod(coords.y, 1.0f) * get_height(); + return game_manager.map.get_province_index_at(x_mod_w, y_mod_h); +} + +#define KEY(x) static const StringName x##_key = #x; +Dictionary GameSingleton::get_province_info_from_index(int32_t index) const { + Province const* province = game_manager.map.get_province_by_index(index); + if (province == nullptr) return {}; + KEY(province) KEY(region) KEY(life_rating) KEY(buildings) + Dictionary ret; + + ret[province_key] = province->get_identifier().c_str(); + + Region const* region = province->get_region(); + if (region != nullptr) ret[region_key] = region->get_identifier().c_str(); + + ret[life_rating_key] = province->get_life_rating(); + + std::vector const& buildings = province->get_buildings(); + if (!buildings.empty()) { + Array buildings_array; + buildings_array.resize(buildings.size()); + for (size_t idx = 0; idx < buildings.size(); ++idx) { + KEY(building) KEY(level) KEY(expansion_state) KEY(start_date) KEY(end_date) KEY(expansion_progress) + + Dictionary building_dict; + Building const& building = buildings[idx]; + building_dict[building_key] = building.get_type().get_identifier().c_str(); + building_dict[level_key] = static_cast(building.get_level()); + building_dict[expansion_state_key] = static_cast(building.get_expansion_state()); + building_dict[start_date_key] = static_cast(building.get_start_date()).c_str(); + building_dict[end_date_key] = static_cast(building.get_end_date()).c_str(); + building_dict[expansion_progress_key] = building.get_expansion_progress(); + + buildings_array[idx] = building_dict; + } + ret[buildings_key] = buildings_array; + } + return ret; +} +#undef KEY + +int32_t GameSingleton::get_width() const { + return game_manager.map.get_width(); +} + +int32_t GameSingleton::get_height() const { + return game_manager.map.get_height(); +} + +Ref GameSingleton::get_province_index_image() const { + return province_index_image; +} + +Ref GameSingleton::get_province_colour_image() const { + return province_colour_image; +} + +Error GameSingleton::update_colour_image() { + static PackedByteArray colour_data_array; + static constexpr int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 4; + 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) + err = FAILED; + + static constexpr int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); + if (province_colour_image.is_null()) + province_colour_image.instantiate(); + province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, + false, Image::FORMAT_RGBA8, colour_data_array); + if (province_colour_image.is_null()) { + UtilityFunctions::push_error("Failed to update province colour image"); + return FAILED; + } + return err; +} + +int32_t GameSingleton::get_mapmode_count() const { + return game_manager.map.get_mapmode_count(); +} + +String GameSingleton::get_mapmode_identifier(int32_t index) const { + Mapmode const* mapmode = game_manager.map.get_mapmode_by_index(index); + if (mapmode != nullptr) return mapmode->get_identifier().c_str(); + return String{}; +} + +Error GameSingleton::set_mapmode(godot::String const& identifier) { + Mapmode const* mapmode = game_manager.map.get_mapmode_by_identifier(identifier.utf8().get_data()); + if (mapmode == nullptr) { + UtilityFunctions::push_error("Failed to set mapmode to: ", identifier); + return FAILED; + } + mapmode_index = mapmode->get_index(); + return OK; +} + +Error GameSingleton::expand_building(int32_t province_index, String const& building_type_identifier) { + if (game_manager.expand_building(province_index, building_type_identifier.utf8().get_data()) != SUCCESS) { + UtilityFunctions::push_error("Failed to expand ", building_type_identifier, " at province index ", province_index); + return FAILED; + } + return OK; +} + +void GameSingleton::set_paused(bool paused) { + game_manager.clock.isPaused = paused; +} + +void GameSingleton::toggle_paused() { + game_manager.clock.isPaused = !game_manager.clock.isPaused; +} + +bool GameSingleton::is_paused() const { + return game_manager.clock.isPaused; +} + +void GameSingleton::increase_speed() { + game_manager.clock.increaseSimulationSpeed(); +} + +void GameSingleton::decrease_speed() { + game_manager.clock.decreaseSimulationSpeed(); +} + +bool GameSingleton::can_increase_speed() const { + return game_manager.clock.canIncreaseSimulationSpeed(); +} + +bool GameSingleton::can_decrease_speed() const { + return game_manager.clock.canDecreaseSimulationSpeed(); +} + +String GameSingleton::get_longform_date() const { + return static_cast(game_manager.get_today()).c_str(); +} + +void GameSingleton::try_tick() { + game_manager.clock.conditionallyAdvanceGame(); +} diff --git a/extension/src/GameSingleton.hpp b/extension/src/GameSingleton.hpp new file mode 100644 index 0000000..0e2cfd1 --- /dev/null +++ b/extension/src/GameSingleton.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include + +#include "openvic2/GameManager.hpp" + +namespace OpenVic2 { + class GameSingleton : public godot::Object { + GDCLASS(GameSingleton, godot::Object) + + static GameSingleton* singleton; + + GameManager game_manager; + + godot::Ref province_index_image, province_colour_image; + Mapmode::index_t mapmode_index = 0; + + 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); + void _tick(); + protected: + static void _bind_methods(); + + public: + static GameSingleton* get_singleton(); + + GameSingleton(); + ~GameSingleton(); + + 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_province_shape_file(godot::String const& file_path); + void finished_loading_data(); + + int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const; + godot::Dictionary get_province_info_from_index(int32_t index) const; + int32_t get_width() const; + int32_t get_height() const; + godot::Ref get_province_index_image() const; + godot::Ref get_province_colour_image() const; + + godot::Error update_colour_image(); + int32_t get_mapmode_count() const; + godot::String get_mapmode_identifier(int32_t index) const; + godot::Error set_mapmode(godot::String const& identifier); + + godot::Error expand_building(int32_t province_index, godot::String const& building_type_identifier); + + void set_paused(bool paused); + void toggle_paused(); + bool is_paused() const; + void increase_speed(); + void decrease_speed(); + bool can_increase_speed() const; + bool can_decrease_speed() const; + godot::String get_longform_date() const; + void try_tick(); + }; +} diff --git a/extension/src/MapSingleton.cpp b/extension/src/MapSingleton.cpp deleted file mode 100644 index 6f90dee..0000000 --- a/extension/src/MapSingleton.cpp +++ /dev/null @@ -1,394 +0,0 @@ -#include "MapSingleton.hpp" - -#include -#include -#include - -using namespace godot; -using namespace OpenVic2; - -MapSingleton* MapSingleton::singleton = nullptr; - -void MapSingleton::_bind_methods() { - ClassDB::bind_method(D_METHOD("load_province_identifier_file", "file_path"), &MapSingleton::load_province_identifier_file); - ClassDB::bind_method(D_METHOD("load_water_province_file", "file_path"), &MapSingleton::load_water_province_file); - ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &MapSingleton::load_region_file); - ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &MapSingleton::load_province_shape_file); - - ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &MapSingleton::get_province_index_from_uv_coords); - ClassDB::bind_method(D_METHOD("get_province_identifier_from_uv_coords", "coords"), &MapSingleton::get_province_identifier_from_uv_coords); - ClassDB::bind_method(D_METHOD("get_region_identifier_from_province_identifier", "identifier"), &MapSingleton::get_region_identifier_from_province_identifier); - ClassDB::bind_method(D_METHOD("get_width"), &MapSingleton::get_width); - ClassDB::bind_method(D_METHOD("get_height"), &MapSingleton::get_height); - ClassDB::bind_method(D_METHOD("get_province_index_image"), &MapSingleton::get_province_index_image); - ClassDB::bind_method(D_METHOD("get_province_colour_image"), &MapSingleton::get_province_colour_image); - - ClassDB::bind_method(D_METHOD("update_colour_image"), &MapSingleton::update_colour_image); - ClassDB::bind_method(D_METHOD("get_mapmode_count"), &MapSingleton::get_mapmode_count); - ClassDB::bind_method(D_METHOD("get_mapmode_identifier", "index"), &MapSingleton::get_mapmode_identifier); - ClassDB::bind_method(D_METHOD("set_mapmode", "identifier"), &MapSingleton::set_mapmode); -} - -MapSingleton* MapSingleton::get_singleton() { - return singleton; -} - -/* REQUIREMENTS: - * MAP-21, MAP-25 - */ -MapSingleton::MapSingleton() { - ERR_FAIL_COND(singleton != nullptr); - singleton = this; - - using mapmode_t = std::pair; - const std::vector mapmodes = { - { "mapmode_province", [](Map const&, Province const& province) -> Province::colour_t { return province.get_colour(); } }, - { "mapmode_region", [](Map const&, Province const& province) -> Province::colour_t { - Region const* region = province.get_region(); - if (region != nullptr) return region->get_colour(); - return province.get_colour(); - } }, - { "mapmode_terrain", [](Map const&, Province const& province) -> Province::colour_t { - return province.is_water() ? 0x4287F5 : 0x0D7017; - } }, - { "mapmode_index", [](Map const& map, Province const& province) -> Province::colour_t { - const uint8_t f = float(province.get_index()) / float(map.get_province_count()) * 255.0f; - return (f << 16) | (f << 8) | f; - } } - }; - std::string error_message; - for (mapmode_t const& mapmode : mapmodes) - if (map.add_mapmode(mapmode.first, mapmode.second, error_message) != SUCCESS) - UtilityFunctions::push_error(error_message.c_str()); -} - -MapSingleton::~MapSingleton() { - ERR_FAIL_COND(singleton != this); - singleton = nullptr; -} - -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 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(); - JSON json; - 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; - -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; -} - -Error MapSingleton::_parse_province_identifier_entry(String const& identifier, Variant const& entry) { - const Variant::Type type = entry.get_type(); - Province::colour_t colour = Province::NULL_COLOUR; - if (type == Variant::ARRAY) { - Array const& colour_array = entry; - if (colour_array.size() == 3) { - for (int jdx = 0; jdx < 3; ++jdx) { - Variant const& var = colour_array[jdx]; - if (var.get_type() != Variant::FLOAT) { - colour = Province::NULL_COLOUR; - break; - } - const double colour_double = var; - if (std::trunc(colour_double) != colour_double) { - colour = Province::NULL_COLOUR; - break; - } - const int64_t colour_int = static_cast(colour_double); - if (colour_int < 0 || colour_int > 255) { - colour = Province::NULL_COLOUR; - break; - } - colour = (colour << 8) | colour_int; - } - } - } else if (type == Variant::STRING) { - String const& colour_string = entry; - if (colour_string.is_valid_hex_number()) { - const int64_t colour_int = colour_string.hex_to_int(); - if (0 <= colour_int && colour_int <= 0xFFFFFF) - colour = colour_int; - } - } - if (colour == Province::NULL_COLOUR) { - UtilityFunctions::push_error("Invalid colour for province identifier \"", identifier, "\": ", entry); - return FAILED; - } - std::string error_message; - if (map.add_province(identifier.utf8().get_data(), colour, error_message) != SUCCESS) { - UtilityFunctions::push_error(error_message.c_str()); - return FAILED; - } - return OK; -} - -Error MapSingleton::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 this->_parse_province_identifier_entry(identifier, entry); - }); - map.lock_provinces(); - return err; -} - -Error MapSingleton::_parse_region_entry(String const& identifier, Variant const& entry) { - Error err = OK; - Variant::Type type = entry.get_type(); - std::vector 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(province_string.utf8().get_data()); - } 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::string error_message; - if (map.add_region(identifier.utf8().get_data(), province_identifiers, error_message) != SUCCESS) { - UtilityFunctions::push_error(error_message.c_str()); - return FAILED; - } - return err; -} - -Error MapSingleton::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 this->_parse_region_entry(identifier, entry); - }); - map.lock_regions(); - return err; -} - -Error MapSingleton::load_province_shape_file(String const& file_path) { - if (province_index_image.is_valid()) { - UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); - return FAILED; - } - Ref province_shape_image; - province_shape_image.instantiate(); - Error err = province_shape_image->load(file_path); - if (err != OK) { - UtilityFunctions::push_error("Failed to load province shape file: ", file_path); - return err; - } - int32_t width = province_shape_image->get_width(); - int32_t height = province_shape_image->get_height(); - if (width < 1 || height < 1) { - UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); - err = FAILED; - } - static const Image::Format expected_format = Image::FORMAT_RGB8; - const Image::Format format = province_shape_image->get_format(); - if (format != expected_format) { - UtilityFunctions::push_error("Invalid format (", format, ", should be ", expected_format, ") for province shape file: ", file_path); - err = FAILED; - } - if (err != OK) return err; - - std::string error_message; - if (map.generate_province_index_image(width, height, province_shape_image->get_data().ptr(), error_message) != SUCCESS) { - UtilityFunctions::push_error(error_message.c_str()); - err = FAILED; - } - - PackedByteArray index_data_array; - index_data_array.resize(width * height * sizeof(Province::index_t)); - memcpy(index_data_array.ptrw(), map.get_province_index_image().data(), index_data_array.size()); - - province_index_image = Image::create_from_data(width, height, false, Image::FORMAT_RG8, index_data_array); - if (province_index_image.is_null()) { - UtilityFunctions::push_error("Failed to create province ID image"); - err = FAILED; - } - - if (update_colour_image() != OK) err = FAILED; - - return err; -} - -Error MapSingleton::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; - std::string error_message; - 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 (map.set_water_province(identifier.utf8().get_data(), error_message) != SUCCESS) { - UtilityFunctions::push_error(error_message.c_str()); - err = FAILED; - } - } - } - map.lock_water_provinces(); - return err; -} - -Province* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) { - if (province_index_image.is_valid()) { - const PackedByteArray index_data_array = province_index_image->get_data(); - Province::index_t const* index_data = reinterpret_cast(index_data_array.ptr()); - const int32_t x_mod_w = UtilityFunctions::fposmod(coords.x, 1.0f) * get_width(); - const int32_t y_mod_h = UtilityFunctions::fposmod(coords.y, 1.0f) * get_height(); - return map.get_province_by_index(index_data[x_mod_w + y_mod_h * get_width()]); - } - return nullptr; -} - -Province const* MapSingleton::get_province_from_uv_coords(godot::Vector2 const& coords) const { - if (province_index_image.is_valid()) { - const PackedByteArray index_data_array = province_index_image->get_data(); - Province::index_t const* index_data = reinterpret_cast(index_data_array.ptr()); - const int32_t x_mod_w = UtilityFunctions::fposmod(coords.x, 1.0f) * get_width(); - const int32_t y_mod_h = UtilityFunctions::fposmod(coords.y, 1.0f) * get_height(); - return map.get_province_by_index(index_data[x_mod_w + y_mod_h * get_width()]); - } - return nullptr; -} - -int32_t MapSingleton::get_province_index_from_uv_coords(Vector2 const& coords) const { - Province const* province = get_province_from_uv_coords(coords); - if (province != nullptr) return province->get_index(); - return Province::NULL_INDEX; -} - -String MapSingleton::get_province_identifier_from_uv_coords(Vector2 const& coords) const { - Province const* province = get_province_from_uv_coords(coords); - if (province != nullptr) return province->get_identifier().c_str(); - return String{}; -} - -String MapSingleton::get_region_identifier_from_province_identifier(String const& identifier) const { - Province const* province = map.get_province_by_identifier(identifier.utf8().get_data()); - if (province != nullptr) { - Region const* region = province->get_region(); - if (region != nullptr) return region->get_identifier().c_str(); - } - return String{}; -} - -int32_t MapSingleton::get_width() const { - return map.get_width(); -} - -int32_t MapSingleton::get_height() const { - return map.get_height(); -} - -Ref MapSingleton::get_province_index_image() const { - return province_index_image; -} - -Ref MapSingleton::get_province_colour_image() const { - return province_colour_image; -} - -Error MapSingleton::update_colour_image() { - static PackedByteArray colour_data_array; - static const int64_t colour_data_array_size = (Province::MAX_INDEX + 1) * 4; - colour_data_array.resize(colour_data_array_size); - - Error err = OK; - std::string error_message; - if (map.generate_mapmode_colours(mapmode_index, colour_data_array.ptrw(), error_message) != SUCCESS) { - UtilityFunctions::push_error(error_message.c_str()); - err = FAILED; - } - - static const int32_t PROVINCE_INDEX_SQRT = 1 << (sizeof(Province::index_t) * 4); - if (province_colour_image.is_null()) - province_colour_image.instantiate(); - province_colour_image->set_data(PROVINCE_INDEX_SQRT, PROVINCE_INDEX_SQRT, - false, Image::FORMAT_RGBA8, colour_data_array); - if (province_colour_image.is_null()) { - UtilityFunctions::push_error("Failed to update province colour image"); - return FAILED; - } - return err; -} - -int32_t MapSingleton::get_mapmode_count() const { - return map.get_mapmode_count(); -} - -String MapSingleton::get_mapmode_identifier(int32_t index) const { - Mapmode const* mapmode = map.get_mapmode_by_index(index); - if (mapmode != nullptr) return mapmode->get_identifier().c_str(); - return String{}; -} - -Error MapSingleton::set_mapmode(godot::String const& identifier) { - Mapmode const* mapmode = map.get_mapmode_by_identifier(identifier.utf8().get_data()); - if (mapmode != nullptr) { - mapmode_index = mapmode->get_index(); - return OK; - } else { - UtilityFunctions::push_error("Failed to set mapmode to: ", identifier); - return FAILED; - } -} diff --git a/extension/src/MapSingleton.hpp b/extension/src/MapSingleton.hpp deleted file mode 100644 index 6ec2ea4..0000000 --- a/extension/src/MapSingleton.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include - -#include - -#include "openvic2/Map.hpp" - -namespace OpenVic2 { - class MapSingleton : public godot::Object { - GDCLASS(MapSingleton, godot::Object) - - static MapSingleton* singleton; - - godot::Ref province_index_image, province_colour_image; - Map map; - Mapmode::index_t mapmode_index = 0; - - 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); - protected: - static void _bind_methods(); - - public: - static MapSingleton* get_singleton(); - - MapSingleton(); - ~MapSingleton(); - - 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_province_shape_file(godot::String const& file_path); - - Province* get_province_from_uv_coords(godot::Vector2 const& coords); - Province const* get_province_from_uv_coords(godot::Vector2 const& coords) const; - int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const; - godot::String get_province_identifier_from_uv_coords(godot::Vector2 const& coords) const; - godot::String get_region_identifier_from_province_identifier(godot::String const& identifier) const; - int32_t get_width() const; - int32_t get_height() const; - godot::Ref get_province_index_image() const; - godot::Ref get_province_colour_image() const; - - godot::Error update_colour_image(); - int32_t get_mapmode_count() const; - godot::String get_mapmode_identifier(int32_t index) const; - godot::Error set_mapmode(godot::String const& identifier); - }; -} diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp index e1cef72..bb891fd 100644 --- a/extension/src/openvic2/Date.cpp +++ b/extension/src/openvic2/Date.cpp @@ -1,115 +1,161 @@ -#include -#include "Date.hpp" +#include "openvic2/Date.hpp" + +#include +#include + +#include "openvic2/Logger.hpp" using namespace OpenVic2; -bool Timespan::operator< (Timespan const& other) const { return days < other.days; } -bool Timespan::operator> (Timespan const& other) const { return days > other.days; } -bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; } -bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; } -bool Timespan::operator== (Timespan const& other) const { return days == other.days; } -bool Timespan::operator!= (Timespan const& other) const { return days != other.days; } +Timespan::Timespan(day_t value) : days{value} {} + +bool Timespan::operator<(Timespan other) const { return days < other.days; }; +bool Timespan::operator>(Timespan other) const { return days > other.days; }; +bool Timespan::operator<=(Timespan other) const { return days <= other.days; }; +bool Timespan::operator>=(Timespan other) const { return days >= other.days; }; +bool Timespan::operator==(Timespan other) const { return days == other.days; }; +bool Timespan::operator!=(Timespan other) const { return days != other.days; }; + +Timespan Timespan::operator+(Timespan other) const { return days + other.days; } + +Timespan Timespan::operator-(Timespan other) const { return days - other.days; } -Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); } -Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); } -Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); } -Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); } +Timespan Timespan::operator*(day_t factor) const { return days * factor; } -Timespan& Timespan::operator+= (Timespan const& other) { +Timespan Timespan::operator/(day_t factor) const { return days / factor; } + +Timespan& Timespan::operator+=(Timespan other) { days += other.days; return *this; } -Timespan& Timespan::operator-= (Timespan const& other) { + +Timespan& Timespan::operator-=(Timespan other) { days -= other.days; return *this; } -Timespan::operator std::string() const { - return std::to_string(days); +Timespan& Timespan::operator++() { + days++; + return *this; } -std::ostream &operator<<(std::ostream &out, Timespan const& timespan) { - return out << static_cast(timespan); + +Timespan Timespan::operator++(int) { + Timespan old = *this; + ++(*this); + return old; } -Timespan fromYearZero(year_t year, month_t month, date_t day) { - int64_t daysElapsed = year * DAYS_IN_YEAR; - size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection - for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) { - daysElapsed += DAYS_IN_MONTH[x]; - } - daysElapsed += daysSinceMonthStart; - return Timespan(daysElapsed); +Timespan::operator day_t() const { + return days; } -//This function is not set up to handle dates before Year 0 -YearMonthDayBundle toGregorianDate(Timespan const& timespan) { - year_t year = 0; - month_t month = 0; - date_t day = 0; +Timespan::operator double() const { + return days; +} - if (timespan >= 0) { - year = timespan.days / DAYS_IN_YEAR; - int64_t remainingDays = timespan.days % DAYS_IN_YEAR; +Timespan::operator std::string() const { + return std::to_string(days); +} + +std::ostream& OpenVic2::operator<<(std::ostream& out, Timespan timespan) { + return out << static_cast(timespan); +} - for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) { - remainingDays -= DAYS_IN_MONTH[x]; - month++; - } +Timespan Date::_dateToTimespan(year_t year, month_t month, day_t day) { + month = std::clamp(month, 1, MONTHS_IN_YEAR); + day = std::clamp(day, 1, DAYS_IN_MONTH[month - 1]); + return year * DAYS_IN_YEAR + DAYS_UP_TO_MONTH[month - 1] + day - 1; +} - //Corrects month and day to be 1-indexed - month++; - day++; +Date::Date(Timespan total_days) : timespan{ total_days } { + if (timespan < 0) { + Logger::error("Invalid timespan for date: ", timespan, " (cannot be negative)"); + timespan = 0; } - return std::make_tuple(year, month, day); } +Date::Date(year_t year, month_t month, day_t day) : timespan{ _dateToTimespan(year, month, day) } {} -Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); } +Date::year_t Date::getYear() const { + return static_cast(timespan) / DAYS_IN_YEAR; +} -Date::Date(year_t year, month_t month, date_t day) { - ts = fromYearZero(year, month, day); - updateDate(ts); +Date::month_t Date::getMonth() const { + return ((static_cast(timespan) % DAYS_IN_YEAR) / 32) + 1; } -void Date::updateDate(Timespan const& timespan) { - gregorianDate = toGregorianDate(timespan); +Date::day_t Date::getDay() const { + const Timespan::day_t days_in_year = static_cast(timespan) % DAYS_IN_YEAR; + return days_in_year - DAYS_UP_TO_MONTH[days_in_year / 32] + 1; } -size_t Date::getDay() const { return std::get<2>(gregorianDate); } -size_t Date::getMonth() const { return std::get<1>(gregorianDate); } -size_t Date::getYear() const { return std::get<0>(gregorianDate); } -bool Date::operator< (Date const& other) const { return ts < other.ts; } -bool Date::operator> (Date const& other) const { return ts > other.ts; } -bool Date::operator<= (Date const& other) const { return ts <= other.ts; } -bool Date::operator>= (Date const& other) const { return ts >= other.ts; } -bool Date::operator== (Date const& other) const { return ts == other.ts; } -bool Date::operator!= (Date const& other) const { return ts != other.ts; } +bool Date::operator<(Date other) const { return timespan < other.timespan; }; +bool Date::operator>(Date other) const { return timespan > other.timespan; }; +bool Date::operator<=(Date other) const { return timespan <= other.timespan; }; +bool Date::operator>=(Date other) const { return timespan >= other.timespan; }; +bool Date::operator==(Date other) const { return timespan == other.timespan; }; +bool Date::operator!=(Date other) const { return timespan != other.timespan; }; + +Date Date::operator+(Timespan other) const { return timespan + other; } + +Timespan Date::operator-(Date other) const { return timespan - other.timespan; } -Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); } -Timespan Date::operator- (Date const& other) const { return ts - other.ts; } +Date& Date::operator+=(Timespan other) { + timespan += other; + return *this; +} -Date& Date::operator+= (Timespan const& timespan) { - ts += timespan; - updateDate(ts); +Date& Date::operator-=(Timespan other) { + timespan -= other; return *this; } -Date& Date::operator-= (Timespan const& timespan) { - ts -= timespan; - updateDate(ts); + +Date& Date::operator++() { + timespan++; return *this; } -Date Date::operator++ (int) { - Date oldCopy = *this; - (*this) += 1; - return oldCopy; + +Date Date::operator++(int) { + Date old = *this; + ++(*this); + return old; } Date::operator std::string() const { std::stringstream ss; - ss << getYear() << '.' << getMonth() << '.' << getDay(); + ss << *this; return ss.str(); } -std::ostream &operator<<(std::ostream &out, Date const& date) { - return out << static_cast(date); + +std::ostream& OpenVic2::operator<<(std::ostream& out, Date date) { + return out << (int) date.getYear() << '.' << (int) date.getMonth() << '.' << (int) date.getDay(); } + +// Parsed from string of the form YYYY.MM.DD +Date Date::from_string(std::string const& date) { + year_t year = 0; + month_t month = 1; + day_t day = 1; + + size_t first_pos = 0; + while (first_pos < date.length() && std::isdigit(date[first_pos++])); + year = atoi(date.substr(0, first_pos).c_str()); + if (first_pos < date.length()) { + if (date[first_pos] == '.') { + size_t second_pos = first_pos + 1; + while (second_pos < date.length() && std::isdigit(date[second_pos++])); + month = atoi(date.substr(first_pos, second_pos - first_pos).c_str()); + if (second_pos < date.length()) { + if (date[second_pos] == '.') { + size_t third_pos = second_pos + 1; + while (third_pos < date.length() && std::isdigit(date[third_pos++])); + day = atoi(date.substr(second_pos, third_pos - second_pos).c_str()); + if (third_pos < date.length()) + Logger::error("Unexpected string \"", date.substr(third_pos), "\" at the end of date ", date); + } else Logger::error("Unexpected character \"", date[second_pos], "\" in date ", date); + } + } else Logger::error("Unexpected character \"", date[first_pos], "\" in date ", date); + } + return _dateToTimespan(year, month, day); +}; diff --git a/extension/src/openvic2/Date.hpp b/extension/src/openvic2/Date.hpp index 9ed5963..b19602b 100644 --- a/extension/src/openvic2/Date.hpp +++ b/extension/src/openvic2/Date.hpp @@ -1,86 +1,83 @@ #pragma once #include -#include -#include #include -#include +#include namespace OpenVic2 { - //A relative period between points in time, measured in days + // A relative period between points in time, measured in days struct Timespan { - int64_t days; - - Timespan() : days(0) {} - Timespan(int64_t const& value) : days(value) {} - - bool operator< (Timespan const& other) const; - bool operator> (Timespan const& other) const; - bool operator<= (Timespan const& other) const; - bool operator>= (Timespan const& other) const; - bool operator== (Timespan const& other) const; - bool operator!= (Timespan const& other) const; - - Timespan operator+ (Timespan const& other) const; - Timespan operator- (Timespan const& other) const; - Timespan operator* (int64_t const& factor) const; - Timespan operator/ (int64_t const& factor) const; - - Timespan& operator+= (Timespan const& other); - Timespan& operator-= (Timespan const& other); - + using day_t = int64_t; + private: + day_t days; + public: + Timespan(day_t value = 0); + + bool operator<(Timespan other) const; + bool operator>(Timespan other) const; + bool operator<=(Timespan other) const; + bool operator>=(Timespan other) const; + bool operator==(Timespan other) const; + bool operator!=(Timespan other) const; + + Timespan operator+(Timespan other) const; + Timespan operator-(Timespan other) const; + Timespan operator*(day_t factor) const; + Timespan operator/(day_t factor) const; + Timespan& operator+=(Timespan other); + Timespan& operator-=(Timespan other); + Timespan& operator++(); + Timespan operator++(int); + + explicit operator day_t() const; + explicit operator double() const; explicit operator std::string() const; - friend std::ostream& operator<< (std::ostream& out, Timespan const& timespan); }; + std::ostream& operator<< (std::ostream& out, Timespan timespan); - static constexpr size_t MONTHS_IN_YEAR = 12; - static constexpr size_t DAYS_IN_YEAR = 365; - static constexpr size_t DAYS_IN_MONTH[MONTHS_IN_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - using date_t = uint8_t; - using month_t = uint8_t; - using year_t = uint16_t; - using YearMonthDayBundle = std::tuple; - - //Represents an in-game date - //Note: Current implementation does not account for leap-years, or dates before Year 0 + // Represents an in-game date + // Note: Current implementation does not account for leap-years, or dates before Year 0 struct Date { - private: - YearMonthDayBundle gregorianDate; - //Number of days since Jan 1st, Year 0 - Timespan ts; - - public: - //The Timespan is considered to be the number of days since Jan 1st, Year 0 - Date(Timespan const& timespan); - - //Year month day specification - Date(year_t year = 1836, month_t month = 1, date_t day = 1); - - private: - void updateDate(Timespan const& timespan); - - public: - size_t getDay() const; - size_t getMonth() const; - size_t getYear() const; - - bool operator< (Date const& other) const; - bool operator> (Date const& other) const; - bool operator<= (Date const& other) const; - bool operator>= (Date const& other) const; - bool operator== (Date const& other) const; - bool operator!= (Date const& other) const; - - Date operator+ (Timespan timespan) const; - Timespan operator- (Date const& other) const; - - Date& operator+= (Timespan const& timespan); - Date& operator-= (Timespan const& timespan); - //Postfix increment - Date operator++ (int); + using year_t = uint16_t; + using month_t = uint8_t; + using day_t = uint8_t; + + static constexpr Timespan::day_t MONTHS_IN_YEAR = 12; + static constexpr Timespan::day_t DAYS_IN_YEAR = 365; + static constexpr Timespan::day_t DAYS_IN_MONTH[MONTHS_IN_YEAR] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + static constexpr Timespan::day_t DAYS_UP_TO_MONTH[MONTHS_IN_YEAR] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + private: + // Number of days since Jan 1st, Year 0 + Timespan timespan; + + static Timespan _dateToTimespan(year_t year, month_t month, day_t day); + public: + // The Timespan is considered to be the number of days since Jan 1st, Year 0 + Date(Timespan total_days); + // Year month day specification + Date(year_t year = 0, month_t month = 1, day_t day = 1); + + year_t getYear() const; + month_t getMonth() const; + day_t getDay() const; + + bool operator<(Date other) const; + bool operator>(Date other) const; + bool operator<=(Date other) const; + bool operator>=(Date other) const; + bool operator==(Date other) const; + bool operator!=(Date other) const; + + Date operator+(Timespan other) const; + Timespan operator-(Date other) const; + Date& operator+=(Timespan other); + Date& operator-=(Timespan other); + Date& operator++(); + Date operator++(int); explicit operator std::string() const; - friend std::ostream& operator<< (std::ostream& out, Date const& date); + // Parsed from string of the form YYYY.MM.DD + static Date from_string(std::string const& date); }; + std::ostream& operator<< (std::ostream& out, Date date); } diff --git a/extension/src/openvic2/GameAdvancementHook.cpp b/extension/src/openvic2/GameAdvancementHook.cpp index 3db3224..c78847b 100644 --- a/extension/src/openvic2/GameAdvancementHook.cpp +++ b/extension/src/openvic2/GameAdvancementHook.cpp @@ -1,69 +1,67 @@ -#include "GameAdvancementHook.hpp" +#include "openvic2/GameAdvancementHook.hpp" -namespace OpenVic2 { - GameAdvancementHook::GameAdvancementHook(AdvancementFunction function, bool startPaused, GameSpeed startingSpeed) { - triggerFunction = function; - lastPolledTime = std::chrono::high_resolution_clock::now(); - isPaused = startPaused; - currentSpeed = startingSpeed; - } +using namespace OpenVic2; - void GameAdvancementHook::increaseSimulationSpeed() { - switch (currentSpeed) { - case(GameSpeed::Speed1): - currentSpeed = GameSpeed::Speed2; - break; - case(GameSpeed::Speed2): - currentSpeed = GameSpeed::Speed3; - break; - case(GameSpeed::Speed3): - currentSpeed = GameSpeed::Speed4; - break; - case(GameSpeed::Speed4): - currentSpeed = GameSpeed::Speed5; - break; - } - } +const std::vector GameAdvancementHook::GAME_SPEEDS = { + std::chrono::milliseconds{ 4000 }, + std::chrono::milliseconds{ 3000 }, + std::chrono::milliseconds{ 2000 }, + std::chrono::milliseconds{ 1000 }, + std::chrono::milliseconds{ 100 }, + std::chrono::milliseconds{ 1 } }; - void GameAdvancementHook::decreaseSimulationSpeed() { - switch (currentSpeed) { - case(GameSpeed::Speed2): - currentSpeed = GameSpeed::Speed1; - break; - case(GameSpeed::Speed3): - currentSpeed = GameSpeed::Speed2; - break; - case(GameSpeed::Speed4): - currentSpeed = GameSpeed::Speed3; - break; - case(GameSpeed::Speed5): - currentSpeed = GameSpeed::Speed4; - break; - } - } +GameAdvancementHook::GameAdvancementHook(AdvancementFunction tickFunction, RefreshFunction updateFunction, bool startPaused, speed_t startingSpeed) + : triggerFunction{ tickFunction }, refreshFunction{ updateFunction }, isPaused{ startPaused } { + lastPolledTime = std::chrono::high_resolution_clock::now(); + setSimulationSpeed(startingSpeed); +} + +void GameAdvancementHook::setSimulationSpeed(speed_t speed) { + if (speed < 0) + currentSpeed = 0; + else if (speed >= GAME_SPEEDS.size()) + currentSpeed = GAME_SPEEDS.size() - 1; + else + currentSpeed = speed; +} + +GameAdvancementHook::speed_t GameAdvancementHook::getSimulationSpeed() const { + return currentSpeed; +} + +void GameAdvancementHook::increaseSimulationSpeed() { + setSimulationSpeed(currentSpeed + 1); +} + +void GameAdvancementHook::decreaseSimulationSpeed() { + setSimulationSpeed(currentSpeed - 1); +} + +bool GameAdvancementHook::canIncreaseSimulationSpeed() const { + return currentSpeed + 1 < GAME_SPEEDS.size(); +} + +bool GameAdvancementHook::canDecreaseSimulationSpeed() const { + return currentSpeed > 0; +} - GameAdvancementHook GameAdvancementHook::operator++(int) { - GameAdvancementHook oldCopy = *this; - increaseSimulationSpeed(); - return oldCopy; - }; +GameAdvancementHook& GameAdvancementHook::operator++() { + increaseSimulationSpeed(); + return *this; +}; - GameAdvancementHook GameAdvancementHook::operator--(int) { - GameAdvancementHook oldCopy = *this; - decreaseSimulationSpeed(); - return oldCopy; - }; +GameAdvancementHook& GameAdvancementHook::operator--() { + decreaseSimulationSpeed(); + return *this; +}; - void GameAdvancementHook::conditionallyAdvanceGame() { - if (!isPaused) { - std::chrono::time_point previousTime = lastPolledTime; - std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); - if (std::chrono::duration_cast(currentTime - previousTime).count() >= static_cast(currentSpeed)) { - lastPolledTime = currentTime; - if (triggerFunction) { - triggerFunction(); - } - } +void GameAdvancementHook::conditionallyAdvanceGame() { + if (!isPaused) { + std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration_cast(currentTime - lastPolledTime) >= GAME_SPEEDS[currentSpeed]) { + lastPolledTime = currentTime; + if (triggerFunction) triggerFunction(); } } -} \ No newline at end of file + if (refreshFunction) refreshFunction(); +} diff --git a/extension/src/openvic2/GameAdvancementHook.hpp b/extension/src/openvic2/GameAdvancementHook.hpp index 72af4ac..572494a 100644 --- a/extension/src/openvic2/GameAdvancementHook.hpp +++ b/extension/src/openvic2/GameAdvancementHook.hpp @@ -2,39 +2,40 @@ #include #include +#include namespace OpenVic2 { - //Value of different game speeds are the minimum number of miliseconds before the simulation advances - enum class GameSpeed { - Speed1 = 4000, - Speed2 = 3000, - Speed3 = 2000, - Speed4 = 1000, - Speed5 = 100, - Speed6 = 1 - }; - //Conditionally advances game with provided behaviour //Class governs game speed and pause state class GameAdvancementHook { public: using AdvancementFunction = std::function; + using RefreshFunction = std::function; + using speed_t = int8_t; + + //Minimum number of miliseconds before the simulation advances + static const std::vector GAME_SPEEDS; private: std::chrono::time_point lastPolledTime; //A function pointer that advances the simulation, intended to be a capturing lambda or something similar. May need to be reworked later AdvancementFunction triggerFunction; + RefreshFunction refreshFunction; public: bool isPaused; - GameSpeed currentSpeed; + speed_t currentSpeed; - GameAdvancementHook(AdvancementFunction function = nullptr, bool startPaused = false, GameSpeed startingSpeed = GameSpeed::Speed1); + GameAdvancementHook(AdvancementFunction tickFunction, RefreshFunction updateFunction, bool startPaused = false, speed_t startingSpeed = 0); + void setSimulationSpeed(speed_t speed); + speed_t getSimulationSpeed() const; void increaseSimulationSpeed(); void decreaseSimulationSpeed(); - GameAdvancementHook operator++(int); - GameAdvancementHook operator--(int); + bool canIncreaseSimulationSpeed() const; + bool canDecreaseSimulationSpeed() const; + GameAdvancementHook& operator++(); + GameAdvancementHook& operator--(); void conditionallyAdvanceGame(); }; } \ No newline at end of file diff --git a/extension/src/openvic2/GameManager.cpp b/extension/src/openvic2/GameManager.cpp new file mode 100644 index 0000000..da742ca --- /dev/null +++ b/extension/src/openvic2/GameManager.cpp @@ -0,0 +1,43 @@ +#include "openvic2/GameManager.hpp" + +#include "openvic2/Logger.hpp" + +using namespace OpenVic2; + +GameManager::GameManager(state_updated_func_t state_updated_callback) + : clock{ [this]() { tick(); }, [this]() { update_state(); }, true }, today{ 1836 }, state_updated{ state_updated_callback } {} + +void GameManager::set_needs_update() { + needs_update = true; +} + +void GameManager::update_state() { + if (needs_update) { + Logger::info("Update: ", today); + map.update_state(today); + if (state_updated) state_updated(); + needs_update = false; + } +} + +void GameManager::tick() { + today++; + Logger::info("Tick: ", today); + map.tick(today); + set_needs_update(); +} + +void GameManager::finished_loading_data() { + map.generate_province_buildings(building_manager); +} + +Date const& GameManager::get_today() const { + return today; +} + +return_t GameManager::expand_building(Province::index_t province_index, std::string const& building_type_identifier) { + set_needs_update(); + Province* province = map.get_province_by_index(province_index); + if (province == nullptr) return FAILURE; + return province->expand_building(building_type_identifier); +} diff --git a/extension/src/openvic2/GameManager.hpp b/extension/src/openvic2/GameManager.hpp new file mode 100644 index 0000000..cba0180 --- /dev/null +++ b/extension/src/openvic2/GameManager.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "openvic2/GameAdvancementHook.hpp" +#include "openvic2/map/Map.hpp" + +namespace OpenVic2 { + struct GameManager { + using state_updated_func_t = std::function; + + Map map; + BuildingManager building_manager; + GameAdvancementHook clock; + private: + Date today; + state_updated_func_t state_updated; + bool needs_update = true; + + void set_needs_update(); + void update_state(); + void tick(); + public: + GameManager(state_updated_func_t state_updated_callback); + + void finished_loading_data(); + + Date const& get_today() const; + return_t expand_building(Province::index_t province_index, std::string const& building_type_identifier); + }; +} diff --git a/extension/src/openvic2/Logger.cpp b/extension/src/openvic2/Logger.cpp new file mode 100644 index 0000000..f211e7e --- /dev/null +++ b/extension/src/openvic2/Logger.cpp @@ -0,0 +1,26 @@ +#include "openvic2/Logger.hpp" + +#include + +using namespace OpenVic2; + +Logger::log_func_t Logger::info_func = [](std::string&& str) { std::cout << str; }; +Logger::log_func_t Logger::error_func = [](std::string&& str) { std::cerr << str; }; + +const char* Logger::get_filename(const char* filepath) { + if (filepath == nullptr) return nullptr; + const char *last_slash = filepath; + while (*filepath != '\0') { + if (*filepath == '\\' || *filepath == '/') last_slash = filepath + 1; + filepath++; + } + return last_slash; +} + +void Logger::set_info_func(log_func_t log_func) { + info_func = log_func; +} + +void Logger::set_error_func(log_func_t log_func) { + error_func = log_func; +} diff --git a/extension/src/openvic2/Logger.hpp b/extension/src/openvic2/Logger.hpp new file mode 100644 index 0000000..749c67f --- /dev/null +++ b/extension/src/openvic2/Logger.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#ifdef __cpp_lib_source_location +#include +#endif + +namespace OpenVic2 { + + #ifndef __cpp_lib_source_location + #include + //Implementation of std::source_location for compilers that do not support it + //Note: uses non-standard extensions that are supported by Clang, GCC, and MSVC + //https://clang.llvm.org/docs/LanguageExtensions.html#source-location-builtins + //https://stackoverflow.com/a/67970107 + class source_location { + std::string _file; + int _line; + std::string _function; + + public: + source_location(std::string f, int l, std::string n) : _file(f), _line(l), _function(n) {} + static source_location current(std::string f = __builtin_FILE(), int l = __builtin_LINE(), std::string n = __builtin_FUNCTION()) { + return source_location(f, l, n); + } + + inline const char* file_name() const { return _file.c_str(); } + inline int line() const {return _line; } + inline const char* function_name() const { return _function.c_str(); } + }; + #endif + + class Logger { + using log_func_t = std::function; + + #ifdef __cpp_lib_source_location + using source_location = std::source_location; + #else + using source_location = OpenVic2::source_location; + #endif + + static log_func_t info_func, error_func; + + static const char* get_filename(const char* filepath); + + template + struct log { + log(log_func_t log_func, Ts&&... ts, const source_location& location) { + if (log_func) { + std::stringstream stream; + stream << std::endl << get_filename(location.file_name()) << "(" << location.line() << ") `" << location.function_name() << "`: "; + ((stream << std::forward(ts)), ...); + stream << std::endl; + log_func(stream.str()); + } + } + }; + public: + static void set_info_func(log_func_t log_func); + static void set_error_func(log_func_t log_func); + + template + struct info { + info(Ts&&... ts, const source_location& location = source_location::current()) { + log{ info_func, std::forward(ts)..., location }; + } + }; + + template + info(Ts&&...) -> info; + + template + struct error { + error(Ts&&... ts, const source_location& location = source_location::current()) { + log{ error_func, std::forward(ts)..., location }; + } + }; + + template + error(Ts&&...) -> error; + }; +} diff --git a/extension/src/openvic2/Map.cpp b/extension/src/openvic2/Map.cpp deleted file mode 100644 index 0ac8091..0000000 --- a/extension/src/openvic2/Map.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "Map.hpp" - -#include -#include - -using namespace OpenVic2; - -static const std::string SEPARATOR = "\n - "; - -Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func) - : HasIdentifier(new_identifier), index(new_index), colour_func(new_colour_func) { - assert(colour_func != nullptr); -} - -Mapmode::index_t Mapmode::get_index() const { - return index; -} - -Mapmode::colour_func_t Mapmode::get_colour_func() const { - return colour_func; -} - -return_t Map::add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message) { - if (provinces_locked) { - error_message = "The map's province list has already been locked!"; - return FAILURE; - } - if (provinces.size() >= Province::MAX_INDEX) { - error_message = "The map's province list is full - there can be at most " + std::to_string(Province::MAX_INDEX) + " provinces"; - return FAILURE; - } - if (identifier.empty()) { - error_message = "Empty province identifier for colour " + Province::colour_to_hex_string(colour); - return FAILURE; - } - if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { - error_message = "Invalid province colour: " + Province::colour_to_hex_string(colour); - return FAILURE; - } - Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; - Province const* old_province = get_province_by_identifier(identifier); - if (old_province != nullptr) { - error_message = "Duplicate province identifiers: " + old_province->to_string() + " and " + new_province.to_string(); - return FAILURE; - } - old_province = get_province_by_colour(colour); - if (old_province != nullptr) { - error_message = "Duplicate province colours: " + old_province->to_string() + " and " + new_province.to_string(); - return FAILURE; - } - provinces.push_back(new_province); - error_message = "Added province: " + new_province.to_string(); - return SUCCESS; -} - -void Map::lock_provinces() { - provinces_locked = true; -} - -return_t Map::set_water_province(std::string const& identifier, std::string& error_message) { - if (water_provinces_locked) { - error_message = "The map's water provinces have already been locked!"; - return FAILURE; - } - Province* province = get_province_by_identifier(identifier); - if (province == nullptr) { - error_message = "Unrecognised water province identifier: " + identifier; - return FAILURE; - } - if (province->is_water()) { - error_message = "Province " + identifier + " is already a water province!"; - return FAILURE; - } - province->water = true; - error_message = "Set province " + identifier + " as a water province"; - return SUCCESS; -} - -void Map::lock_water_provinces() { - water_provinces_locked = true; -} - -return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message) { - if (regions_locked) { - error_message = "The map's region list has already been locked!"; - return FAILURE; - } - if (identifier.empty()) { - error_message = "Empty region identifier!"; - return FAILURE; - } - if (provinces.empty()) { - error_message = "Empty province list for region " + identifier; - return FAILURE; - } - Region new_region{ identifier }; - error_message.clear(); - for (std::string const& province_identifier : province_identifiers) { - Province* province = get_province_by_identifier(province_identifier); - if (province != nullptr) { - if (new_region.contains_province(province)) - error_message += SEPARATOR + "Duplicate province identifier " + province_identifier; - else { - size_t other_region_index = reinterpret_cast(province->get_region()); - if (other_region_index != 0) { - other_region_index--; - error_message += SEPARATOR + "Province " + province_identifier + " is already part of "; - if (other_region_index < regions.size()) - error_message += regions[other_region_index].get_identifier(); - else - error_message += "an unknown region with index " + std::to_string(other_region_index); - } else new_region.provinces.insert(province); - } - } else error_message += SEPARATOR + "Invalid province identifier " + province_identifier; - } - return_t ret = SUCCESS; - if (!new_region.get_province_count()) { - error_message += SEPARATOR + "No valid provinces in region's list"; - ret = FAILURE; - } - Region const* old_region = get_region_by_identifier(identifier); - if (old_region != nullptr) { - error_message += SEPARATOR + "Duplicate region identifiers: " + old_region->get_identifier() + " and " + identifier; - ret = FAILURE; - } - - if (ret == SUCCESS) { - regions.push_back(new_region); - // Used to detect provinces listed in multiple regions, will - // be corrected once regions is stable (i.e. lock_regions). - Region* tmp_region_index = reinterpret_cast(regions.size()); - for (Province* province : new_region.get_provinces()) - province->region = tmp_region_index; - if (!error_message.empty()) { - error_message += SEPARATOR; - ret = FAILURE; - } - error_message += "Added region: " + identifier; - } - if (ret != SUCCESS) error_message = "Error message for region: " + identifier + error_message; - return ret; -} - -void Map::lock_regions() { - regions_locked = true; - for (Region& region : regions) - for (Province* province : region.get_provinces()) - province->region = ®ion; -} - -size_t Map::get_province_count() const { - return provinces.size(); -} - -Province* Map::get_province_by_index(Province::index_t index) { - return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; -} - -Province const* Map::get_province_by_index(Province::index_t index) const { - return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; -} - -Province* Map::get_province_by_identifier(std::string const& identifier) { - if (!identifier.empty()) - for (Province& province : provinces) - if (province.get_identifier() == identifier) return &province; - return nullptr; -} - -Province const* Map::get_province_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Province const& province : provinces) - if (province.get_identifier() == identifier) return &province; - return nullptr; -} - -Province* Map::get_province_by_colour(Province::colour_t colour) { - if (colour != Province::NULL_COLOUR) - for (Province& province : provinces) - if (province.get_colour() == colour) return &province; - return nullptr; -} - -Province const* Map::get_province_by_colour(Province::colour_t colour) const { - if (colour != Province::NULL_COLOUR) - for (Province const& province : provinces) - if (province.get_colour() == colour) return &province; - return nullptr; -} - -Region* Map::get_region_by_identifier(std::string const& identifier) { - if (!identifier.empty()) - for (Region& region : regions) - if (region.get_identifier() == identifier) return ®ion; - return nullptr; -} - -Region const* Map::get_region_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Region const& region : regions) - if (region.get_identifier() == identifier) return ®ion; - return nullptr; -} - -static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) { - return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2]; -} - -return_t Map::generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message) { - if (!province_index_image.empty()) { - error_message = "Province index image has already been generated!"; - return FAILURE; - } - if (!provinces_locked) { - error_message = "Province index image cannot be generated until after provinces are locked!"; - return FAILURE; - } - if (new_width < 1 || new_height < 1) { - error_message = "Invalid province image dimensions: " + std::to_string(new_width) + "x" + std::to_string(new_height); - return FAILURE; - } - if (colour_data == nullptr) { - error_message = "Province colour data pointer is null!"; - return FAILURE; - } - width = new_width; - height = new_height; - province_index_image.resize(width * height); - - std::vector province_checklist(provinces.size()); - return_t ret = SUCCESS; - std::unordered_set unrecognised_colours; - error_message.clear(); - - for (int32_t y = 0; y < height; ++y) { - for (int32_t x = 0; x < width; ++x) { - const int32_t idx = x + y * width; - const Province::colour_t colour = colour_at(colour_data, idx); - if (x > 0) { - const int32_t jdx = idx - 1; - if (colour_at(colour_data, jdx) == colour) { - province_index_image[idx] = province_index_image[jdx]; - continue; - } - } - if (y > 0) { - const int32_t jdx = idx - width; - if (colour_at(colour_data, jdx) == colour) { - province_index_image[idx] = province_index_image[jdx]; - continue; - } - } - Province const* province = get_province_by_colour(colour); - if (province != nullptr) { - const Province::index_t index = province->get_index(); - province_index_image[idx] = index; - province_checklist[index - 1] = true; - continue; - } - if (unrecognised_colours.find(colour) == unrecognised_colours.end()) { - unrecognised_colours.insert(colour); - error_message += SEPARATOR + "Unrecognised province colour " + Province::colour_to_hex_string(colour) + " at (" + std::to_string(x) + ", " + std::to_string(y) + ")"; - ret = FAILURE; - } - province_index_image[idx] = Province::NULL_INDEX; - } - } - - for (size_t idx = 0; idx < province_checklist.size(); ++idx) { - if (!province_checklist[idx]) { - error_message += SEPARATOR + "Province missing from shape image: " + provinces[idx].to_string(); - ret = FAILURE; - } - } - - if (!error_message.empty()) error_message = "Error message for province index image generation:" + error_message + SEPARATOR; - error_message += "Generated province index image"; - return ret; -} - -size_t Map::get_width() const { - return width; -} - -size_t Map::get_height() const { - return height; -} - -std::vector const& Map::get_province_index_image() const { - return province_index_image; -} - -return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message) { - if (identifier.empty()) { - error_message = "Empty mapmode identifier!"; - return FAILURE; - } - if (colour_func == nullptr) { - error_message = "Mapmode colour function is null for identifier: " + identifier; - return FAILURE; - } - Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func }; - Mapmode const* old_mapmode = get_mapmode_by_identifier(identifier); - if (old_mapmode != nullptr) { - error_message = "Duplicate mapmode identifiers: " + old_mapmode->get_identifier() + " and " + identifier; - return FAILURE; - } - mapmodes.push_back(new_mapmode); - error_message = "Added mapmode: " + identifier; - return SUCCESS; -} - -size_t Map::get_mapmode_count() const { - return mapmodes.size(); -} - -Mapmode const* Map::get_mapmode_by_index(size_t index) const { - return index < mapmodes.size() ? &mapmodes[index] : nullptr; -} - -Mapmode const* Map::get_mapmode_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Mapmode const& mapmode : mapmodes) - if (mapmode.get_identifier() == identifier) return &mapmode; - return nullptr; -} - -return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const { - if (target == nullptr) { - error_message = "Mapmode colour target pointer is null!"; - return FAILURE; - } - if (index >= mapmodes.size()) { - error_message = "Invalid mapmode index: " + std::to_string(index); - return FAILURE; - } - Mapmode const& mapmode = mapmodes[index]; - target += 4; // Skip past Province::NULL_INDEX - for (Province const& province : provinces) { - const Province::colour_t colour = mapmode.get_colour_func()(*this, province); - *target++ = (colour >> 16) & 0xFF; - *target++ = (colour >> 8) & 0xFF; - *target++ = colour & 0xFF; - *target++ = province.is_water() ? 0 : 255; - } - error_message = "Generated province colours for mapmode " + mapmode.get_identifier(); - return SUCCESS; -} diff --git a/extension/src/openvic2/Map.hpp b/extension/src/openvic2/Map.hpp deleted file mode 100644 index 73ab8fd..0000000 --- a/extension/src/openvic2/Map.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include - -#include "Region.hpp" - -namespace OpenVic2 { - - struct Mapmode : HasIdentifier { - friend struct Map; - - using colour_func_t = std::function; - using index_t = size_t; - private: - index_t index; - colour_func_t colour_func; - - Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); - public: - index_t get_index() const; - colour_func_t get_colour_func() const; - }; - - /* REQUIREMENTS: - * MAP-4 - */ - struct Map { - private: - std::vector provinces; - std::vector regions; - bool provinces_locked = false, water_provinces_locked = false, regions_locked = false; - - size_t width = 0, height = 0; - std::vector province_index_image; - std::vector mapmodes; - public: - return_t add_province(std::string const& identifier, Province::colour_t colour, std::string& error_message); - void lock_provinces(); - return_t set_water_province(std::string const& identifier, std::string& error_message); - void lock_water_provinces(); - return_t add_region(std::string const& identifier, std::vector const& province_identifiers, std::string& error_message); - void lock_regions(); - - size_t get_province_count() const; - Province* get_province_by_index(Province::index_t index); - Province const* get_province_by_index(Province::index_t index) const; - Province* get_province_by_identifier(std::string const& identifier); - Province const* get_province_by_identifier(std::string const& identifier) const; - Province* get_province_by_colour(Province::colour_t colour); - Province const* get_province_by_colour(Province::colour_t colour) const; - - Region* get_region_by_identifier(std::string const& identifier); - Region const* get_region_by_identifier(std::string const& identifier) const; - - return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data, std::string& error_message); - size_t get_width() const; - size_t get_height() const; - std::vector const& get_province_index_image() const; - - return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func, std::string& error_message); - size_t get_mapmode_count() const; - Mapmode const* get_mapmode_by_index(Mapmode::index_t index) const; - Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; - return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target, std::string& error_message) const; - }; -} diff --git a/extension/src/openvic2/Province.cpp b/extension/src/openvic2/Province.cpp deleted file mode 100644 index 7d55708..0000000 --- a/extension/src/openvic2/Province.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "Province.hpp" - -#include -#include -#include - -using namespace OpenVic2; - -Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : - HasIdentifier(new_identifier), index(new_index), colour(new_colour) { - assert(index != NULL_INDEX); - assert(colour != NULL_COLOUR); -} - -std::string Province::colour_to_hex_string(colour_t colour) { - std::ostringstream stream; - stream << std::hex << std::setfill('0') << std::setw(6) << colour; - return stream.str(); -} - -Province::index_t Province::get_index() const { - return index; -} - -Province::colour_t Province::get_colour() const { - return colour; -} - -Region* Province::get_region() const { - return region; -} - -bool Province::is_water() const { - return water; -} - -Province::life_rating_t Province::get_life_rating() const { - return life_rating; -} - -std::string Province::to_string() const { - return "(#" + std::to_string(index) + ", " + get_identifier() + ", 0x" + colour_to_hex_string(colour) + ")"; -} diff --git a/extension/src/openvic2/Province.hpp b/extension/src/openvic2/Province.hpp deleted file mode 100644 index deebd8c..0000000 --- a/extension/src/openvic2/Province.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "Types.hpp" - -namespace OpenVic2 { - struct Region; - struct Map; - - /* REQUIREMENTS: - * MAP-5, MAP-8, MAP-43, MAP-47 - */ - struct Province : HasIdentifier { - friend struct Map; - - using colour_t = uint32_t; - using index_t = uint16_t; - using life_rating_t = int8_t; - - static const colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; - static const index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; - private: - index_t index; - colour_t colour; - Region* region = nullptr; - bool water = false; - life_rating_t life_rating = 0; - - Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); - public: - static std::string colour_to_hex_string(colour_t colour); - - index_t get_index() const; - colour_t get_colour() const; - Region* get_region() const; - bool is_water() const; - life_rating_t get_life_rating() const; - std::string to_string() const; - }; -} diff --git a/extension/src/openvic2/Region.cpp b/extension/src/openvic2/Region.cpp deleted file mode 100644 index 67a75a9..0000000 --- a/extension/src/openvic2/Region.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "Region.hpp" - -#include -#include - -using namespace OpenVic2; - -size_t ProvinceSet::get_province_count() const { - return provinces.size(); -} - -bool ProvinceSet::contains_province(Province const* province) const { - return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); -} - -std::set const& ProvinceSet::get_provinces() const { - return provinces; -} - -Region::Region(std::string const& new_identifier) : HasIdentifier(new_identifier) {} - -Province::colour_t Region::get_colour() const { - if (provinces.empty()) return 0xFF0000; - Province const* province = *provinces.cbegin(); - return province->get_colour(); -} diff --git a/extension/src/openvic2/Region.hpp b/extension/src/openvic2/Region.hpp deleted file mode 100644 index 4ebabd1..0000000 --- a/extension/src/openvic2/Region.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "Province.hpp" - -namespace OpenVic2 { - struct Map; - - struct ProvinceSet { - protected: - std::set provinces; - public: - size_t get_province_count() const; - bool contains_province(Province const* province) const; - std::set const& get_provinces() const; - }; - - /* REQUIREMENTS: - * MAP-6, MAP-44, MAP-48 - */ - struct Region : HasIdentifier, ProvinceSet { - friend struct Map; - private: - Region(std::string const& new_identifier); - public: - Province::colour_t get_colour() const; - }; -} diff --git a/extension/src/openvic2/Types.cpp b/extension/src/openvic2/Types.cpp index 67c7a21..861ab50 100644 --- a/extension/src/openvic2/Types.cpp +++ b/extension/src/openvic2/Types.cpp @@ -1,10 +1,10 @@ -#include "Types.hpp" +#include "openvic2/Types.hpp" #include using namespace OpenVic2; -HasIdentifier::HasIdentifier(std::string const& new_identifier) : identifier(new_identifier) { +HasIdentifier::HasIdentifier(std::string const& new_identifier) : identifier{ new_identifier } { assert(!identifier.empty()); } diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp index bf5ee27..b20db10 100644 --- a/extension/src/openvic2/Types.hpp +++ b/extension/src/openvic2/Types.hpp @@ -1,14 +1,16 @@ #pragma once #include +#include + +#include "openvic2/Logger.hpp" namespace OpenVic2 { using return_t = bool; // This mirrors godot::Error, where `OK = 0` and `FAILED = 1`. - static const return_t SUCCESS = false, FAILURE = true; + static constexpr return_t SUCCESS = false, FAILURE = true; - struct HasIdentifier { - private: + class HasIdentifier { std::string identifier; protected: HasIdentifier(std::string const& new_identifier); diff --git a/extension/src/openvic2/map/Building.cpp b/extension/src/openvic2/map/Building.cpp new file mode 100644 index 0000000..f453a0f --- /dev/null +++ b/extension/src/openvic2/map/Building.cpp @@ -0,0 +1,129 @@ +#include "openvic2/map/Building.hpp" + +#include + +#include "openvic2/Logger.hpp" + +using namespace OpenVic2; + +Building::Building(BuildingType const& new_type) : type{ new_type } {} + +bool Building::_can_expand() const { + return level < type.get_max_level(); +} + +BuildingType const& Building::get_type() const { + return type; +} + +Building::level_t Building::get_level() const { + return level; +} + +Building::ExpansionState Building::get_expansion_state() const { + return expansion_state; +} + +Date const& Building::get_start_date() const { + return start; +} + +Date const& Building::get_end_date() const { + return end; +} + +float Building::get_expansion_progress() const { + return expansion_progress; +} + +return_t Building::expand() { + if (expansion_state == ExpansionState::CanExpand) { + expansion_state = ExpansionState::Preparing; + expansion_progress = 0.0f; + return SUCCESS; + } + return FAILURE; +} + +void Building::update_state(Date const& today) { + switch (expansion_state) { + case ExpansionState::Preparing: + start = today; + end = start + type.get_build_time(); + break; + case ExpansionState::Expanding: + expansion_progress = static_cast(today - start) / static_cast(end - start); + break; + default: expansion_state = _can_expand() ? ExpansionState::CanExpand : ExpansionState::CannotExpand; + } +} + +void Building::tick(Date const& today) { + if (expansion_state == ExpansionState::Preparing) { + expansion_state = ExpansionState::Expanding; + } + if (expansion_state == ExpansionState::Expanding) { + if (end <= today) { + level++; + expansion_state = ExpansionState::CannotExpand; + } + } +} + +BuildingType::BuildingType(std::string const& new_identifier, Building::level_t new_max_level, Timespan new_build_time) : + HasIdentifier{ new_identifier }, max_level{ new_max_level }, build_time{ new_build_time } { + assert(new_max_level >= 0); + assert(build_time >= 0); +} + +Building::level_t BuildingType::get_max_level() const { + return max_level; +} + +Timespan BuildingType::get_build_time() const { + return build_time; +} + +return_t BuildingManager::add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time) { + if (building_types_locked) { + Logger::error("The building type list has already been locked!"); + return FAILURE; + } + if (identifier.empty()) { + Logger::error("Empty building type identifier!"); + return FAILURE; + } + if (max_level < 0) { + Logger::error("Invalid building type max level: ", max_level); + return FAILURE; + } + if (build_time < 0) { + Logger::error("Invalid building type build time: ", build_time); + return FAILURE; + } + BuildingType new_building_type{ identifier, max_level, build_time }; + BuildingType const* old_building_type = get_building_type_by_identifier(identifier); + if (old_building_type != nullptr) { + Logger::error("Duplicate building type identifiers: ", old_building_type->get_identifier(), " and ", identifier); + return FAILURE; + } + building_types.push_back(new_building_type); + return SUCCESS; +} + +void BuildingManager::lock_building_types() { + building_types_locked = true; + Logger::info("Locked building types after registering ", building_types.size()); +} + +BuildingType const* BuildingManager::get_building_type_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (BuildingType const& building_type : building_types) + if (building_type.get_identifier() == identifier) return &building_type; + return nullptr; +} + +void BuildingManager::generate_province_buildings(std::vector& buildings) const { + for (BuildingType const& type : building_types) + buildings.push_back(Building{ type }); +} diff --git a/extension/src/openvic2/map/Building.hpp b/extension/src/openvic2/map/Building.hpp new file mode 100644 index 0000000..7a1a777 --- /dev/null +++ b/extension/src/openvic2/map/Building.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "openvic2/Types.hpp" +#include "openvic2/Date.hpp" + +namespace OpenVic2 { + struct BuildingManager; + struct BuildingType; + + struct Building { + friend struct BuildingManager; + + using level_t = int8_t; + + enum class ExpansionState { CannotExpand, CanExpand, Preparing, Expanding }; + private: + BuildingType const& type; + level_t level = 0; + ExpansionState expansion_state = ExpansionState::CannotExpand; + Date start, end; + float expansion_progress; + + Building(BuildingType const& new_type); + + bool _can_expand() const; + public: + BuildingType const& get_type() const; + level_t get_level() const; + ExpansionState get_expansion_state() const; + Date const& get_start_date() const; + Date const& get_end_date() const; + float get_expansion_progress() const; + + return_t expand(); + void update_state(Date const& today); + void tick(Date const& today); + }; + + struct BuildingType : HasIdentifier { + friend struct BuildingManager; + private: + Building::level_t max_level; + Timespan build_time; + + BuildingType(std::string const& new_identifier, Building::level_t new_max_level, Timespan new_build_time); + public: + Building::level_t get_max_level() const; + Timespan get_build_time() const; + }; + + struct BuildingManager { + private: + std::vector building_types; + bool building_types_locked = false; + public: + return_t add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time); + void lock_building_types(); + BuildingType const* get_building_type_by_identifier(std::string const& identifier) const; + void generate_province_buildings(std::vector& buildings) const; + }; +} diff --git a/extension/src/openvic2/map/Map.cpp b/extension/src/openvic2/map/Map.cpp new file mode 100644 index 0000000..1089d61 --- /dev/null +++ b/extension/src/openvic2/map/Map.cpp @@ -0,0 +1,359 @@ +#include "openvic2/map/Map.hpp" + +#include +#include + +#include "openvic2/Logger.hpp" + +using namespace OpenVic2; + +Mapmode::Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func) + : HasIdentifier{ new_identifier }, index{ new_index }, colour_func{ new_colour_func } { + assert(colour_func != nullptr); +} + +Mapmode::index_t Mapmode::get_index() const { + return index; +} + +Mapmode::colour_func_t Mapmode::get_colour_func() const { + return colour_func; +} + +return_t Map::add_province(std::string const& identifier, Province::colour_t colour) { + if (provinces_locked) { + Logger::error("The map's province list has already been locked!"); + return FAILURE; + } + if (provinces.size() >= Province::MAX_INDEX) { + Logger::error("The map's province list is full - there can be at most ", Province::MAX_INDEX, " provinces"); + return FAILURE; + } + if (identifier.empty()) { + Logger::error("Empty province identifier for colour ", Province::colour_to_hex_string(colour)); + return FAILURE; + } + if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { + Logger::error("Invalid province colour: ", Province::colour_to_hex_string(colour)); + return FAILURE; + } + Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; + Province const* old_province = get_province_by_identifier(identifier); + if (old_province != nullptr) { + Logger::error("Duplicate province identifiers: ", old_province->to_string(), " and ", new_province.to_string()); + return FAILURE; + } + old_province = get_province_by_colour(colour); + if (old_province != nullptr) { + Logger::error("Duplicate province colours: ", old_province->to_string(), " and ", new_province.to_string()); + return FAILURE; + } + provinces.push_back(new_province); + return SUCCESS; +} + +void Map::lock_provinces() { + provinces_locked = true; + Logger::info("Locked provinces after registering ", provinces.size()); +} + +return_t Map::set_water_province(std::string const& identifier) { + if (water_provinces_locked) { + Logger::error("The map's water provinces have already been locked!"); + return FAILURE; + } + Province* province = get_province_by_identifier(identifier); + if (province == nullptr) { + Logger::error("Unrecognised water province identifier: ", identifier); + return FAILURE; + } + if (province->is_water()) { + Logger::error("Province ", identifier, " is already a water province!"); + return FAILURE; + } + province->water = true; + water_province_count++; + return SUCCESS; +} + +void Map::lock_water_provinces() { + water_provinces_locked = true; + Logger::info("Locked water provinces after registering ", water_province_count); +} + +return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers) { + if (regions_locked) { + Logger::error("The map's region list has already been locked!"); + return FAILURE; + } + if (identifier.empty()) { + Logger::error("Empty region identifier!"); + return FAILURE; + } + if (provinces.empty()) { + Logger::error("Empty province list for region ", identifier); + return FAILURE; + } + return_t ret = SUCCESS; + Region new_region{ identifier }; + for (std::string const& province_identifier : province_identifiers) { + Province* province = get_province_by_identifier(province_identifier); + if (province != nullptr) { + if (new_region.contains_province(province)) { + Logger::error("Duplicate province identifier ", province_identifier); + ret = FAILURE; + } else { + size_t other_region_index = reinterpret_cast(province->get_region()); + if (other_region_index != 0) { + other_region_index--; + if (other_region_index < regions.size()) + Logger::error("Province ", province_identifier, " is already part of ", regions[other_region_index].get_identifier()); + else + Logger::error("Province ", province_identifier, " is already part of an unknown region with index ", other_region_index); + ret = FAILURE; + } else new_region.provinces.insert(province); + } + } else { + Logger::error("Invalid province identifier ", province_identifier); + ret = FAILURE; + } + } + if (!new_region.get_province_count()) { + Logger::error("No valid provinces in region's list"); + return FAILURE; + } + Region const* old_region = get_region_by_identifier(identifier); + if (old_region != nullptr) { + Logger::error("Duplicate region identifiers: ", old_region->get_identifier(), " and ", identifier); + return FAILURE; + } + + regions.push_back(new_region); + // Used to detect provinces listed in multiple regions, will + // be corrected once regions is stable (i.e. lock_regions). + Region* tmp_region_index = reinterpret_cast(regions.size()); + for (Province* province : new_region.get_provinces()) + province->region = tmp_region_index; + return ret; +} + +void Map::lock_regions() { + regions_locked = true; + for (Region& region : regions) + for (Province* province : region.get_provinces()) + province->region = ®ion; + Logger::info("Locked regions after registering ", regions.size()); +} + +size_t Map::get_province_count() const { + return provinces.size(); +} + +Province* Map::get_province_by_index(Province::index_t index) { + return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; +} + +Province const* Map::get_province_by_index(Province::index_t index) const { + return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; +} + +Province* Map::get_province_by_identifier(std::string const& identifier) { + if (!identifier.empty()) + for (Province& province : provinces) + if (province.get_identifier() == identifier) return &province; + return nullptr; +} + +Province const* Map::get_province_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Province const& province : provinces) + if (province.get_identifier() == identifier) return &province; + return nullptr; +} + +Province* Map::get_province_by_colour(Province::colour_t colour) { + if (colour != Province::NULL_COLOUR) + for (Province& province : provinces) + if (province.get_colour() == colour) return &province; + return nullptr; +} + +Province const* Map::get_province_by_colour(Province::colour_t colour) const { + if (colour != Province::NULL_COLOUR) + for (Province const& province : provinces) + if (province.get_colour() == colour) return &province; + return nullptr; +} + +Province::index_t Map::get_province_index_at(size_t x, size_t y) const { + if (x < width && y < height) return province_index_image[x + y * width]; + return Province::NULL_INDEX; +} + +Region* Map::get_region_by_identifier(std::string const& identifier) { + if (!identifier.empty()) + for (Region& region : regions) + if (region.get_identifier() == identifier) return ®ion; + return nullptr; +} + +Region const* Map::get_region_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Region const& region : regions) + if (region.get_identifier() == identifier) return ®ion; + return nullptr; +} + +static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) { + return (colour_data[idx * 3] << 16) | (colour_data[idx * 3 + 1] << 8) | colour_data[idx * 3 + 2]; +} + +return_t Map::generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data) { + if (!province_index_image.empty()) { + Logger::error("Province index image has already been generated!"); + return FAILURE; + } + if (!provinces_locked) { + Logger::error("Province index image cannot be generated until after provinces are locked!"); + return FAILURE; + } + if (new_width < 1 || new_height < 1) { + Logger::error("Invalid province image dimensions: ", new_width, "x", new_height); + return FAILURE; + } + if (colour_data == nullptr) { + Logger::error("Province colour data pointer is null!"); + return FAILURE; + } + width = new_width; + height = new_height; + province_index_image.resize(width * height); + + std::vector province_checklist(provinces.size()); + return_t ret = SUCCESS; + std::unordered_set unrecognised_colours; + + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + const int32_t idx = x + y * width; + const Province::colour_t colour = colour_at(colour_data, idx); + if (x > 0) { + const int32_t jdx = idx - 1; + if (colour_at(colour_data, jdx) == colour) { + province_index_image[idx] = province_index_image[jdx]; + continue; + } + } + if (y > 0) { + const int32_t jdx = idx - width; + if (colour_at(colour_data, jdx) == colour) { + province_index_image[idx] = province_index_image[jdx]; + continue; + } + } + Province const* province = get_province_by_colour(colour); + if (province != nullptr) { + const Province::index_t index = province->get_index(); + province_index_image[idx] = index; + province_checklist[index - 1] = true; + continue; + } + if (unrecognised_colours.find(colour) == unrecognised_colours.end()) { + unrecognised_colours.insert(colour); + Logger::error("Unrecognised province colour ", Province::colour_to_hex_string(colour), " at (", x, ", ", y, ")"); + ret = FAILURE; + } + province_index_image[idx] = Province::NULL_INDEX; + } + } + + for (size_t idx = 0; idx < province_checklist.size(); ++idx) { + if (!province_checklist[idx]) { + Logger::error("Province missing from shape image: ", provinces[idx].to_string()); + ret = FAILURE; + } + } + return ret; +} + +size_t Map::get_width() const { + return width; +} + +size_t Map::get_height() const { + return height; +} + +std::vector const& Map::get_province_index_image() const { + return province_index_image; +} + +return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func) { + if (identifier.empty()) { + Logger::error("Empty mapmode identifier!"); + return FAILURE; + } + if (colour_func == nullptr) { + Logger::error("Mapmode colour function is null for identifier: ", identifier); + return FAILURE; + } + Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func }; + Mapmode const* old_mapmode = get_mapmode_by_identifier(identifier); + if (old_mapmode != nullptr) { + Logger::error("Duplicate mapmode identifiers: ", old_mapmode->get_identifier(), " and ", identifier); + return FAILURE; + } + mapmodes.push_back(new_mapmode); + return SUCCESS; +} + +size_t Map::get_mapmode_count() const { + return mapmodes.size(); +} + +Mapmode const* Map::get_mapmode_by_index(size_t index) const { + return index < mapmodes.size() ? &mapmodes[index] : nullptr; +} + +Mapmode const* Map::get_mapmode_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (Mapmode const& mapmode : mapmodes) + if (mapmode.get_identifier() == identifier) return &mapmode; + return nullptr; +} + +return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const { + if (target == nullptr) { + Logger::error("Mapmode colour target pointer is null!"); + return FAILURE; + } + if (index >= mapmodes.size()) { + Logger::error("Invalid mapmode index: ", index); + return FAILURE; + } + Mapmode const& mapmode = mapmodes[index]; + target += 4; // Skip past Province::NULL_INDEX + for (Province const& province : provinces) { + const Province::colour_t colour = mapmode.get_colour_func()(*this, province); + *target++ = (colour >> 16) & 0xFF; + *target++ = (colour >> 8) & 0xFF; + *target++ = colour & 0xFF; + *target++ = province.is_water() ? 0 : 255; + } + return SUCCESS; +} + +void Map::generate_province_buildings(BuildingManager const& manager) { + for (Province& province : provinces) + manager.generate_province_buildings(province.buildings); +} + +void Map::update_state(Date const& today) { + for (Province& province : provinces) + province.update_state(today); +} + +void Map::tick(Date const& today) { + for (Province& province : provinces) + province.tick(today); +} diff --git a/extension/src/openvic2/map/Map.hpp b/extension/src/openvic2/map/Map.hpp new file mode 100644 index 0000000..b6e7ac2 --- /dev/null +++ b/extension/src/openvic2/map/Map.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include + +#include "openvic2/map/Region.hpp" + +namespace OpenVic2 { + + struct Mapmode : HasIdentifier { + friend struct Map; + + using colour_func_t = std::function; + using index_t = size_t; + private: + index_t index; + colour_func_t colour_func; + + Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); + public: + index_t get_index() const; + colour_func_t get_colour_func() const; + }; + + /* REQUIREMENTS: + * MAP-4 + */ + struct Map { + private: + std::vector provinces; + std::vector regions; + bool provinces_locked = false, water_provinces_locked = false, regions_locked = false; + size_t water_province_count = 0; + + size_t width = 0, height = 0; + std::vector province_index_image; + std::vector mapmodes; + public: + return_t add_province(std::string const& identifier, Province::colour_t colour); + void lock_provinces(); + return_t set_water_province(std::string const& identifier); + void lock_water_provinces(); + return_t add_region(std::string const& identifier, std::vector const& province_identifiers); + void lock_regions(); + + size_t get_province_count() const; + Province* get_province_by_index(Province::index_t index); + Province const* get_province_by_index(Province::index_t index) const; + Province* get_province_by_identifier(std::string const& identifier); + Province const* get_province_by_identifier(std::string const& identifier) const; + Province* get_province_by_colour(Province::colour_t colour); + Province const* get_province_by_colour(Province::colour_t colour) const; + Province::index_t get_province_index_at(size_t x, size_t y) const; + + Region* get_region_by_identifier(std::string const& identifier); + Region const* get_region_by_identifier(std::string const& identifier) const; + + return_t generate_province_index_image(size_t new_width, size_t new_height, uint8_t const* colour_data); + size_t get_width() const; + size_t get_height() const; + std::vector const& get_province_index_image() const; + + return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func); + size_t get_mapmode_count() const; + Mapmode const* get_mapmode_by_index(Mapmode::index_t index) const; + Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; + return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; + + void generate_province_buildings(BuildingManager const& manager); + + void update_state(Date const& today); + void tick(Date const& today); + }; +} diff --git a/extension/src/openvic2/map/Province.cpp b/extension/src/openvic2/map/Province.cpp new file mode 100644 index 0000000..c641b7e --- /dev/null +++ b/extension/src/openvic2/map/Province.cpp @@ -0,0 +1,67 @@ +#include "openvic2/map/Province.hpp" + +#include +#include +#include + +using namespace OpenVic2; + +Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : + HasIdentifier{ new_identifier }, index{ new_index }, colour{ new_colour } { + assert(index != NULL_INDEX); + assert(colour != NULL_COLOUR); +} + +std::string Province::colour_to_hex_string(colour_t colour) { + std::ostringstream stream; + stream << std::hex << std::setfill('0') << std::setw(6) << colour; + return stream.str(); +} + +Province::index_t Province::get_index() const { + return index; +} + +Province::colour_t Province::get_colour() const { + return colour; +} + +Region* Province::get_region() const { + return region; +} + +bool Province::is_water() const { + return water; +} + +Province::life_rating_t Province::get_life_rating() const { + return life_rating; +} + +std::vector const& Province::get_buildings() const { + return buildings; +} + +return_t Province::expand_building(std::string const& building_type_identifier) { + for (Building& building : buildings) + if (building.get_type().get_identifier() == building_type_identifier) + return building.expand(); + return FAILURE; +} + +std::string Province::to_string() const { + std::stringstream stream; + stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << colour_to_hex_string(colour) << ")"; + return stream.str(); +} + +void Province::update_state(Date const& today) { + for (Building& building : buildings) + building.update_state(today); + +} + +void Province::tick(Date const& today) { + for (Building& building : buildings) + building.tick(today); +} diff --git a/extension/src/openvic2/map/Province.hpp b/extension/src/openvic2/map/Province.hpp new file mode 100644 index 0000000..79c6861 --- /dev/null +++ b/extension/src/openvic2/map/Province.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "openvic2/map/Building.hpp" + +namespace OpenVic2 { + struct Map; + struct Region; + + /* REQUIREMENTS: + * MAP-5, MAP-8, MAP-43, MAP-47 + */ + struct Province : HasIdentifier { + friend struct Map; + + using colour_t = uint32_t; + using index_t = uint16_t; + using life_rating_t = int8_t; + + static constexpr colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; + static constexpr index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; + private: + index_t index; + colour_t colour; + Region* region = nullptr; + bool water = false; + life_rating_t life_rating = 0; + std::vector buildings; + + Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); + public: + static std::string colour_to_hex_string(colour_t colour); + + index_t get_index() const; + colour_t get_colour() const; + Region* get_region() const; + bool is_water() const; + life_rating_t get_life_rating() const; + std::vector const& get_buildings() const; + return_t expand_building(std::string const& building_type_identifier); + std::string to_string() const; + + void update_state(Date const& today); + void tick(Date const& today); + }; +} diff --git a/extension/src/openvic2/map/Region.cpp b/extension/src/openvic2/map/Region.cpp new file mode 100644 index 0000000..3e5bee7 --- /dev/null +++ b/extension/src/openvic2/map/Region.cpp @@ -0,0 +1,26 @@ +#include "openvic2/map/Region.hpp" + +#include +#include + +using namespace OpenVic2; + +size_t ProvinceSet::get_province_count() const { + return provinces.size(); +} + +bool ProvinceSet::contains_province(Province const* province) const { + return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); +} + +std::set const& ProvinceSet::get_provinces() const { + return provinces; +} + +Region::Region(std::string const& new_identifier) : HasIdentifier{ new_identifier } {} + +Province::colour_t Region::get_colour() const { + if (provinces.empty()) return 0xFF0000; + Province const* province = *provinces.cbegin(); + return province->get_colour(); +} diff --git a/extension/src/openvic2/map/Region.hpp b/extension/src/openvic2/map/Region.hpp new file mode 100644 index 0000000..2eec1cd --- /dev/null +++ b/extension/src/openvic2/map/Region.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "openvic2/map/Province.hpp" + +namespace OpenVic2 { + + struct ProvinceSet { + protected: + std::set provinces; + public: + size_t get_province_count() const; + bool contains_province(Province const* province) const; + std::set const& get_provinces() const; + }; + + /* REQUIREMENTS: + * MAP-6, MAP-44, MAP-48 + */ + struct Region : HasIdentifier, ProvinceSet { + friend struct Map; + private: + Region(std::string const& new_identifier); + public: + Province::colour_t get_colour() const; + }; +} diff --git a/extension/src/register_types.cpp b/extension/src/register_types.cpp index 10ed781..b99f1a8 100644 --- a/extension/src/register_types.cpp +++ b/extension/src/register_types.cpp @@ -4,7 +4,7 @@ #include "Checksum.hpp" #include "LoadLocalisation.hpp" -#include "MapSingleton.hpp" +#include "GameSingleton.hpp" #include "MapMesh.hpp" using namespace godot; @@ -12,7 +12,7 @@ using namespace OpenVic2; static Checksum* _checksum; static LoadLocalisation* _load_localisation; -static MapSingleton* _map_singleton; +static GameSingleton* _map_singleton; void initialize_openvic2_types(ModuleInitializationLevel p_level) { if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { @@ -27,9 +27,9 @@ void initialize_openvic2_types(ModuleInitializationLevel p_level) { _load_localisation = memnew(LoadLocalisation); Engine::get_singleton()->register_singleton("LoadLocalisation", LoadLocalisation::get_singleton()); - ClassDB::register_class(); - _map_singleton = memnew(MapSingleton); - Engine::get_singleton()->register_singleton("MapSingleton", MapSingleton::get_singleton()); + ClassDB::register_class(); + _map_singleton = memnew(GameSingleton); + Engine::get_singleton()->register_singleton("GameSingleton", GameSingleton::get_singleton()); ClassDB::register_class(); } @@ -45,7 +45,7 @@ void uninitialize_openvic2_types(ModuleInitializationLevel p_level) { Engine::get_singleton()->unregister_singleton("LoadLocalisation"); memdelete(_load_localisation); - Engine::get_singleton()->unregister_singleton("MapSingleton"); + Engine::get_singleton()->unregister_singleton("GameSingleton"); memdelete(_map_singleton); } @@ -60,4 +60,4 @@ extern "C" { return init_obj.init(); } -} \ No newline at end of file +} diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv index 33e5c42..c637a39 100644 --- a/game/localisation/en_GB/menus.csv +++ b/game/localisation/en_GB/menus.csv @@ -63,3 +63,12 @@ GAMESESSIONMENU_QUIT_DIALOG_TEXT,Are you sure you want to quit and return to des DIALOG_OK,OK DIALOG_CANCEL,Cancel + +,, Province Overview Panel +province_MISSING,No Province +region_MISSING,No Region +building_MISSING,No Building +building_fort,Fort +building_naval_base,Naval Base +building_railroad,Railroad +EXPAND_PROVINCE_BUILDING,Expand diff --git a/game/localisation/en_GB/provinces.csv b/game/localisation/en_GB/provinces.csv index 814b4f9..8f1679d 100644 --- a/game/localisation/en_GB/provinces.csv +++ b/game/localisation/en_GB/provinces.csv @@ -1,51 +1,51 @@ ,, Europe -prov_britain_NAME,Britain -prov_ireland_NAME,Ireland -prov_iceland_NAME,Iceland -prov_corsica_NAME,Corsica -prov_sardinia_NAME,Sardinia -prov_sicily_NAME,Sicily -prov_malta_NAME,Malta -prov_cyprus_NAME,Cyprus -prov_greenland_NAME,Greenland -prov_baleares_NAME,Balearic Islands -prov_gotland_NAME,Gotland -prov_crete_NAME,Crete -prov_jan_mayen_NAME,Jan Mayen -prov_faroes_NAME,Faroe Islands -prov_mann_NAME,Isle of Mann -prov_shetlands_NAME,Shetlands -prov_orkney_NAME,Orkney -prov_channel_islands_NAME,Channel Islands -prov_madiera_NAME,Madiera -prov_canarias_NAME,Canarias -prov_sjaeland_NAME,Sjaeland -prov_bornholm_NAME,Bornholm -prov_bear_island_NAME,Bear Island -prov_pantelleria_NAME,Pantelleria -prov_iberia_NAME,Iberia -prov_scandinavia_NAME,Scandinavia -prov_jutland_NAME,Jutland -prov_fyn_NAME,Fyn -prov_hiiumaa_NAME,Hiiumaa -prov_saaremaa_NAME,Saaremaa -prov_italy_NAME,Italy -prov_elba_NAME,Elba -prov_france_NAME,France -prov_netherlands_NAME,Netherlands -prov_belgium_NAME,Belgium -prov_luxembourg_NAME,Luxembourg -prov_switzerland_NAME,Switzerland -prov_balkans_NAME,Balkans -prov_crimea_NAME,Crimea -prov_germany_NAME,Germany -prov_poland_NAME,Poland -prov_baltics_NAME,Baltics -prov_finland_NAME,Finland -prov_aland_NAME,Åland -prov_ukraine_NAME,Ukraine -prov_russia_NAME,Russia +prov_britain,Britain +prov_ireland,Ireland +prov_iceland,Iceland +prov_corsica,Corsica +prov_sardinia,Sardinia +prov_sicily,Sicily +prov_malta,Malta +prov_cyprus,Cyprus +prov_greenland,Greenland +prov_baleares,Balearic Islands +prov_gotland,Gotland +prov_crete,Crete +prov_jan_mayen,Jan Mayen +prov_faroes,Faroe Islands +prov_mann,Isle of Mann +prov_shetlands,Shetlands +prov_orkney,Orkney +prov_channel_islands,Channel Islands +prov_madiera,Madiera +prov_canarias,Canarias +prov_sjaeland,Sjaeland +prov_bornholm,Bornholm +prov_bear_island,Bear Island +prov_pantelleria,Pantelleria +prov_iberia,Iberia +prov_scandinavia,Scandinavia +prov_jutland,Jutland +prov_fyn,Fyn +prov_hiiumaa,Hiiumaa +prov_saaremaa,Saaremaa +prov_italy,Italy +prov_elba,Elba +prov_france,France +prov_netherlands,Netherlands +prov_belgium,Belgium +prov_luxembourg,Luxembourg +prov_switzerland,Switzerland +prov_balkans,Balkans +prov_crimea,Crimea +prov_germany,Germany +prov_poland,Poland +prov_baltics,Baltics +prov_finland,Finland +prov_aland,Åland +prov_ukraine,Ukraine +prov_russia,Russia ,, North America prov_north_america_NAME,North America @@ -92,154 +92,154 @@ prov_yellowknife_NAME,Yellowknife prov_iqaluit_NAME,Iqaluit ,, South America -prov_south_america_NAME,South America -prov_galapagos_NAME,Galapagos -prov_falklands_NAME,Falklands -prov_south_georgia_NAME,South Georgia +prov_south_america,South America +prov_galapagos,Galapagos +prov_falklands,Falklands +prov_south_georgia,South Georgia ,, Africa -prov_africa_NAME,Africa -prov_madagascar_NAME,Madagascar -prov_socotra_NAME,Socotra -prov_mauritius_NAME,Mauritius -prov_reunion_NAME,Réunion -prov_comoros_NAME,Comoros -prov_sao_tome_NAME,Sao Tome -prov_fernando_po_NAME,Fernando Po -prov_cape_verde_NAME,Cape Verde -prov_ascension_NAME,Ascension -prov_st_helena_NAME,St Helena -prov_tristan_da_cunha_NAME,Tristan da Cunha -prov_seychelles_NAME,Seychelles -prov_prince_edward_islands_NAME,Prince Edward Islands -prov_kerguelen_islands_NAME,Kerguelen Islands -prov_heard_island_NAME,Heard Island -prov_egypt_NAME,Egypt -prov_morocco_NAME,Morocco +prov_africa,Africa +prov_madagascar,Madagascar +prov_socotra,Socotra +prov_mauritius,Mauritius +prov_reunion,Réunion +prov_comoros,Comoros +prov_sao_tome,Sao Tome +prov_fernando_po,Fernando Po +prov_cape_verde,Cape Verde +prov_ascension,Ascension +prov_st_helena,St Helena +prov_tristan_da_cunha,Tristan da Cunha +prov_seychelles,Seychelles +prov_prince_edward_islands,Prince Edward Islands +prov_kerguelen_islands,Kerguelen Islands +prov_heard_island,Heard Island +prov_egypt,Egypt +prov_morocco,Morocco ,, Asia -prov_middle_east_NAME,Middle East -prov_ceylon_NAME,Ceylon -prov_formosa_NAME,Formosa -prov_sakhalin_NAME,Sakhalin -prov_maldives_NAME,Maldives -prov_hainan_NAME,Hainan -prov_hokkaido_NAME,Hokkaido -prov_diego_garcia_NAME,Diego Garcia -prov_philippines_NAME,Philippines -prov_india_NAME,India -prov_andamans_NAME,Andaman Islands -prov_nicobar_islands_NAME,Nicobar Islands -prov_indochina_NAME,Indochina -prov_korea_NAME,Korea -prov_okinawa_NAME,Okinawa -prov_yaeyama_NAME,Yaeyama -prov_kyushu_NAME,Kyushu -prov_shikoku_NAME,Shikoku -prov_japan_NAME,Japan -prov_kurils_NAME,Kuril Islands -prov_manchuria_NAME,Manchuria -prov_china_NAME,China -prov_central_asia_NAME,Central Asia -prov_siberia_NAME,Siberia -prov_iran_NAME,Iran -prov_anatolia_NAME,Anatolia +prov_middle_east,Middle East +prov_ceylon,Ceylon +prov_formosa,Formosa +prov_sakhalin,Sakhalin +prov_maldives,Maldives +prov_hainan,Hainan +prov_hokkaido,Hokkaido +prov_diego_garcia,Diego Garcia +prov_philippines,Philippines +prov_india,India +prov_andamans,Andaman Islands +prov_nicobar_islands,Nicobar Islands +prov_indochina,Indochina +prov_korea,Korea +prov_okinawa,Okinawa +prov_yaeyama,Yaeyama +prov_kyushu,Kyushu +prov_shikoku,Shikoku +prov_japan,Japan +prov_kurils,Kuril Islands +prov_manchuria,Manchuria +prov_china,China +prov_central_asia,Central Asia +prov_siberia,Siberia +prov_iran,Iran +prov_anatolia,Anatolia ,, Oceania -prov_oceania_NAME,Oceania -prov_indonesia_NAME,Indonesia -prov_north_island_NAME,North Island -prov_south_island_NAME,South Island -prov_tasmania_NAME,Tasmania -prov_australia_NAME,Australia -prov_hawaii_NAME,Hawaii +prov_oceania,Oceania +prov_indonesia,Indonesia +prov_north_island,North Island +prov_south_island,South Island +prov_tasmania,Tasmania +prov_australia,Australia +prov_hawaii,Hawaii ,, Lakes -prov_aral_sea_NAME,Aral Sea -prov_caspian_sea_NAME,Caspian Sea -prov_lake_ladoga_NAME,Lake Ladoga -prov_lake_ontario_NAME,Lake Ontario -prov_lake_erie_NAME,Lake Erie -prov_lake_huron_NAME,Lake Huron -prov_lake_michigan_NAME,Lake Michigan -prov_lake_superior_NAME,Lake Superior -prov_lake_baikal_NAME,Lake Baikal -prov_lake_woods_NAME,Lake of the Woods -prov_lake_manitoba_NAME,Lake Manitoba -prov_reindeer_lake_NAME,Reindeer Lake -prov_lake_ronge_NAME,Lac la Ronge -prov_lake_athabasca_NAME,Lake Athabasca -prov_great_slave_lake_NAME,Great Slave Lake -prov_great_bear_lake_NAME,Great Bear Lake +prov_aral_sea,Aral Sea +prov_caspian_sea,Caspian Sea +prov_lake_ladoga,Lake Ladoga +prov_lake_ontario,Lake Ontario +prov_lake_erie,Lake Erie +prov_lake_huron,Lake Huron +prov_lake_michigan,Lake Michigan +prov_lake_superior,Lake Superior +prov_lake_baikal,Lake Baikal +prov_lake_woods,Lake of the Woods +prov_lake_manitoba,Lake Manitoba +prov_reindeer_lake,Reindeer Lake +prov_lake_ronge,Lac la Ronge +prov_lake_athabasca,Lake Athabasca +prov_great_slave_lake,Great Slave Lake +prov_great_bear_lake,Great Bear Lake ,, Seas and Oceans -prov_azov_sea_NAME,Sea of Azov -prov_black_sea_NAME,Black Sea -prov_marmara_sea_NAME,Sea of Marmara -prov_agean_sea_NAME,Agean Sea -prov_ionian_sea_NAME,Ionian Sea -prov_adriatic_sea_NAME,Adriatic Sea -prov_tyrrhenian_sea_NAME,Tyrrhenian Sea -prov_east_mediterranean_NAME,East Mediterranean Sea -prov_central_mediterranean_NAME,Central Mediterranean Sea -prov_west_mediterranean_NAME,West Mediterranean Sea -prov_ligurian_sea_NAME,Ligurian Sea -prov_balearic_sea_NAME,Balearic Sea -prov_alboran_sea_NAME,Alboran Sea -prov_gulf_bothnia_NAME,Gulf of Bothnia -prov_gulf_finland_NAME,Gulf of Finland -prov_gulf_riga_NAME,Gulf of Riga -prov_baltic_sea_NAME,Baltic Sea -prov_danish_straits_NAME,Danish Straits -prov_english_channel_NAME,English Channel -prov_irish_sea_NAME,Irish Sea -prov_biscay_bay_NAME,Bay of Biscay -prov_north_sea_NAME,North Sea -prov_red_sea_NAME,Red Sea -prov_arabian_sea_NAME,Arabian Sea -prov_persian_gulf_NAME,Persian Gulf -prov_andaman_sea_NAME,Andaman Sea -prov_bay_bengal_NAME,Bay of Bengal -prov_okhotsk_sea_NAME,Sea of Okhotsk -prov_japan_sea_NAME,Sea of Japan -prov_east_china_sea_NAME,East China Sea -prov_south_china_sea_NAME,South China Sea -prov_philippine_sea_NAME,Philippine Sea -prov_celebes_sea_NAME,Celebes Sea -prov_java_sea_NAME,Java Sea -prov_banda_sea_NAME,Banda Sea -prov_arafura_sea_NAME,Arafura Sea -prov_gulf_mexico_NAME,Gulf of Mexico -prov_caribbean_sea_NAME,Caribbean Sea -prov_mozambique_channel_NAME,Mozambique Channel -prov_zanj_sea_NAME,Sea of Zanj -prov_kara_sea_NAME,Kara Sea -prov_barents_sea_NAME,Barents Sea -prov_norwegian_sea_NAME,Norwegian Sea -prov_greenland_sea_NAME,Greenland Sea -prov_labrador_sea_NAME,Labrador Sea -prov_hudson_bay_NAME,Hudson Bay -prov_gulf_st_lawrence_NAME,Gulf of St Lawrence -prov_gulf_alaska_NAME,Gulf of Alaska -prov_gulf_california_NAME,Gulf of California -prov_east_siberian_sea_NAME,East Siberian Sea -prov_sargasso_sea_NAME,Sargasso Sea -prov_gulf_guinea_NAME,Gulf of Guinea -prov_celtic_sea_NAME,Celtic Sea -prov_argentine_sea_NAME,Argentine Sea -prov_chilean_sea_NAME,Chilean Sea -prov_north_atlantic_NAME,North Atlantic Ocean -prov_central_atlantic_NAME,Central Atlantic Ocean -prov_south_atlantic_NAME,South Atlantic Ocean -prov_indian_ocean_NAME,Indian Ocean -prov_great_australian_bight_NAME,Great Australian Bight -prov_tasman_sea_NAME,Tasman Sea -prov_coral_sea_NAME,Coral Sea -prov_melanesia_NAME,Melanesia -prov_micronesia_NAME,Micronesia -prov_polynesia_NAME,Polynesia -prov_north_pacific_NAME,North Pacific Ocean -prov_south_pacific_NAME,South Pacific Ocean -prov_bering_sea_NAME,Bering Sea -prov_chukchi_sea_NAME,Chukchi Sea -prov_beaufort_sea_NAME,Beaufort Sea +prov_azov_sea,Sea of Azov +prov_black_sea,Black Sea +prov_marmara_sea,Sea of Marmara +prov_agean_sea,Agean Sea +prov_ionian_sea,Ionian Sea +prov_adriatic_sea,Adriatic Sea +prov_tyrrhenian_sea,Tyrrhenian Sea +prov_east_mediterranean,East Mediterranean Sea +prov_central_mediterranean,Central Mediterranean Sea +prov_west_mediterranean,West Mediterranean Sea +prov_ligurian_sea,Ligurian Sea +prov_balearic_sea,Balearic Sea +prov_alboran_sea,Alboran Sea +prov_gulf_bothnia,Gulf of Bothnia +prov_gulf_finland,Gulf of Finland +prov_gulf_riga,Gulf of Riga +prov_baltic_sea,Baltic Sea +prov_danish_straits,Danish Straits +prov_english_channel,English Channel +prov_irish_sea,Irish Sea +prov_biscay_bay,Bay of Biscay +prov_north_sea,North Sea +prov_red_sea,Red Sea +prov_arabian_sea,Arabian Sea +prov_persian_gulf,Persian Gulf +prov_andaman_sea,Andaman Sea +prov_bay_bengal,Bay of Bengal +prov_okhotsk_sea,Sea of Okhotsk +prov_japan_sea,Sea of Japan +prov_east_china_sea,East China Sea +prov_south_china_sea,South China Sea +prov_philippine_sea,Philippine Sea +prov_celebes_sea,Celebes Sea +prov_java_sea,Java Sea +prov_banda_sea,Banda Sea +prov_arafura_sea,Arafura Sea +prov_gulf_mexico,Gulf of Mexico +prov_caribbean_sea,Caribbean Sea +prov_mozambique_channel,Mozambique Channel +prov_zanj_sea,Sea of Zanj +prov_kara_sea,Kara Sea +prov_barents_sea,Barents Sea +prov_norwegian_sea,Norwegian Sea +prov_greenland_sea,Greenland Sea +prov_labrador_sea,Labrador Sea +prov_hudson_bay,Hudson Bay +prov_gulf_st_lawrence,Gulf of St Lawrence +prov_gulf_alaska,Gulf of Alaska +prov_gulf_california,Gulf of California +prov_east_siberian_sea,East Siberian Sea +prov_sargasso_sea,Sargasso Sea +prov_gulf_guinea,Gulf of Guinea +prov_celtic_sea,Celtic Sea +prov_argentine_sea,Argentine Sea +prov_chilean_sea,Chilean Sea +prov_north_atlantic,North Atlantic Ocean +prov_central_atlantic,Central Atlantic Ocean +prov_south_atlantic,South Atlantic Ocean +prov_indian_ocean,Indian Ocean +prov_great_australian_bight,Great Australian Bight +prov_tasman_sea,Tasman Sea +prov_coral_sea,Coral Sea +prov_melanesia,Melanesia +prov_micronesia,Micronesia +prov_polynesia,Polynesia +prov_north_pacific,North Pacific Ocean +prov_south_pacific,South Pacific Ocean +prov_bering_sea,Bering Sea +prov_chukchi_sea,Chukchi Sea +prov_beaufort_sea,Beaufort Sea diff --git a/game/localisation/en_GB/regions.csv b/game/localisation/en_GB/regions.csv index 8fe8943..258cce6 100644 --- a/game/localisation/en_GB/regions.csv +++ b/game/localisation/en_GB/regions.csv @@ -1,8 +1,8 @@ ,, Regions -region_europe_NAME,Europe -region_north_america_NAME,North America -region_south_america_NAME,South America -region_africa_NAME,Africa -region_asia_NAME,Asia -region_oceania_NAME,Oceania +region_europe,Europe +region_north_america,North America +region_south_america,South America +region_africa,Africa +region_asia,Asia +region_oceania,Oceania diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index dbd3f9f..0ee2eff 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -11,11 +11,12 @@ const _province_shape_file : String = "res://common/map/provinces.png" # REQUIREMENTS # * FS-333, FS-334, FS-335, FS-341 func _ready(): - if MapSingleton.load_province_identifier_file(_province_identifier_file) != OK: + if GameSingleton.load_province_identifier_file(_province_identifier_file) != OK: push_error("Failed to load province identifiers") - if MapSingleton.load_water_province_file(_water_province_file) != OK: + if GameSingleton.load_water_province_file(_water_province_file) != OK: push_error("Failed to load water provinces") - if MapSingleton.load_region_file(_region_file) != OK: + if GameSingleton.load_region_file(_region_file) != OK: push_error("Failed to load regions") - if MapSingleton.load_province_shape_file(_province_shape_file) != OK: + if GameSingleton.load_province_shape_file(_province_shape_file) != OK: push_error("Failed to load province shapes") + GameSingleton.finished_loading_data() diff --git a/game/src/GameSession/GameSession.gd b/game/src/GameSession/GameSession.gd index fe83a8a..2761815 100644 --- a/game/src/GameSession/GameSession.gd +++ b/game/src/GameSession/GameSession.gd @@ -5,7 +5,10 @@ extends Control func _ready(): Events.Options.load_settings_from_file() +func _process(delta : float): + GameSingleton.try_tick() + # REQUIREMENTS: # * SS-42 -func _on_game_session_menu_button_pressed(): +func _on_game_session_menu_button_pressed() -> void: _game_session_menu.visible = !_game_session_menu.visible diff --git a/game/src/GameSession/GameSessionMenu.gd b/game/src/GameSession/GameSessionMenu.gd index 8a76c0f..7d785ca 100644 --- a/game/src/GameSession/GameSessionMenu.gd +++ b/game/src/GameSession/GameSessionMenu.gd @@ -8,6 +8,7 @@ signal options_button_pressed # * SS-47 # * UIFUN-69 func _on_main_menu_confirmed() -> void: + # TODO - reset map when going back to main menu get_tree().change_scene_to_packed(_main_menu_scene) # REQUIREMENTS: diff --git a/game/src/GameSession/GameSpeedPanel.gd b/game/src/GameSession/GameSpeedPanel.gd index 8dc35d7..c203032 100644 --- a/game/src/GameSession/GameSpeedPanel.gd +++ b/game/src/GameSession/GameSpeedPanel.gd @@ -7,27 +7,32 @@ extends PanelContainer @export var _decrease_speed_button : Button @export var _increase_speed_button : Button -var is_game_paused : bool = true - # Called when the node enters the scene tree for the first time. func _ready(): - _update_playpause_button() + GameSingleton.state_updated.connect(_update_buttons) + _update_buttons() + +func _update_buttons(): + _play_pause_display_button.text = "⏸️" if GameSingleton.is_paused() else "▶" + + _increase_speed_button.disabled = not GameSingleton.can_increase_speed() + _decrease_speed_button.disabled = not GameSingleton.can_decrease_speed() -func _update_playpause_button(): - _play_pause_display_button.text = "⏸️" if is_game_paused else "▶" - print("Game is paused" if is_game_paused else "Game is advancing") + _longform_date_button.text = GameSingleton.get_longform_date() func _on_decrease_speed_button_pressed(): - print("Decrease speed") + GameSingleton.decrease_speed() + _update_buttons() func _on_increase_speed_button_pressed(): - print("Increase speed") + GameSingleton.increase_speed() + _update_buttons() func _on_play_pause_display_button_pressed(): - is_game_paused = !is_game_paused - _update_playpause_button() + GameSingleton.toggle_paused() + _update_buttons() func _on_longform_date_label_pressed(): - is_game_paused = !is_game_paused - _update_playpause_button() + GameSingleton.toggle_paused() + _update_buttons() diff --git a/game/src/GameSession/MapControlPanel.gd b/game/src/GameSession/MapControlPanel.gd index d5810c5..73d7e06 100644 --- a/game/src/GameSession/MapControlPanel.gd +++ b/game/src/GameSession/MapControlPanel.gd @@ -27,8 +27,8 @@ func _add_mapmode_button(identifier : String) -> void: func _ready(): _mapmode_button_group = ButtonGroup.new() _mapmode_button_group.pressed.connect(_mapmode_pressed) - for index in MapSingleton.get_mapmode_count(): - _add_mapmode_button(MapSingleton.get_mapmode_identifier(index)) + for index in GameSingleton.get_mapmode_count(): + _add_mapmode_button(GameSingleton.get_mapmode_identifier(index)) # REQUIREMENTS: # * UIFUN-10 @@ -39,7 +39,7 @@ func _on_game_session_menu_button_pressed() -> void: # * SS-76 # * UIFUN-129, UIFUN-133 func _mapmode_pressed(button : BaseButton) -> void: - MapSingleton.set_mapmode(button.tooltip_text) + GameSingleton.set_mapmode(button.tooltip_text) mapmode_changed.emit() func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void: diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index ae49e82..ac060e1 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -1,6 +1,6 @@ extends Node3D -signal province_selected(identifier : String) +signal province_selected(index : int) signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) const _action_north : StringName = &"map_north" @@ -21,7 +21,7 @@ const _shader_param_terrain_tile_factor : StringName = &"terrain_tile_factor" @export var _camera : Camera3D @export var _cardinal_move_speed : float = 1.0 -@export var _edge_move_threshold: float = 0.02 +@export var _edge_move_threshold: float = 0.01 @export var _edge_move_speed: float = 2.5 var _drag_anchor : Vector2 var _drag_active : bool = false @@ -53,7 +53,7 @@ var _viewport_dims : Vector2 = Vector2(1, 1) # ??? Strange Godot/GDExtension Bug ??? # Upon first opening a clone of this repo with the Godot Editor, -# if MapSingleton.get_province_index_image is called before MapMesh +# if GameSingleton.get_province_index_image is called before MapMesh # is referenced in the script below, then the editor will crash due # to a failed HashMap lookup. I'm not sure if this is a bug in the # editor, GDExtension, my own extension, or a combination of them. @@ -78,7 +78,7 @@ func _ready(): _map_shader_material = map_material # Province index texture - _map_province_index_image = MapSingleton.get_province_index_image() + _map_province_index_image = GameSingleton.get_province_index_image() if _map_province_index_image == null: push_error("Failed to get province index image!") return @@ -86,7 +86,7 @@ func _ready(): _map_shader_material.set_shader_parameter(_shader_param_province_index, province_index_texture) # Province colour texture - _map_province_colour_image = MapSingleton.get_province_colour_image() + _map_province_colour_image = GameSingleton.get_province_colour_image() if _map_province_colour_image == null: push_error("Failed to get province colour image!") return @@ -99,7 +99,7 @@ func _ready(): _map_mesh = _map_mesh_instance.mesh # Set map mesh size and get bounds - _map_image_size = Vector2(Vector2i(MapSingleton.get_width(), MapSingleton.get_height())) + _map_image_size = Vector2(Vector2i(GameSingleton.get_width(), GameSingleton.get_height())) _map_mesh.aspect_ratio = _map_image_size.x / _map_image_size.y _map_shader_material.set_shader_parameter(_shader_param_terrain_tile_factor, _map_image_size.y / 64.0) var map_mesh_aabb := _map_mesh.get_core_aabb() * _map_mesh_instance.transform @@ -120,7 +120,7 @@ func _notification(what : int): _on_mouse_exited_viewport() func _update_colour_texture() -> void: - MapSingleton.update_colour_image() + GameSingleton.update_colour_image() _map_province_colour_texture.update(_map_province_colour_image) func _world_to_map_coords(pos : Vector3) -> Vector2: @@ -151,10 +151,9 @@ func _unhandled_input(event : InputEvent): if _mouse_over_viewport and event.is_action_pressed(_action_click): # Check if the mouse is outside of bounds if _map_mesh.is_valid_uv_coord(_mouse_pos_map): - var selected_index := MapSingleton.get_province_index_from_uv_coords(_mouse_pos_map) + var selected_index := GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map) _map_shader_material.set_shader_parameter(_shader_param_selected_index, selected_index) - var province_identifier := MapSingleton.get_province_identifier_from_uv_coords(_mouse_pos_map) - province_selected.emit(province_identifier) + province_selected.emit(selected_index) else: print("Clicked outside the map!") elif event.is_action_pressed(_action_drag): @@ -248,7 +247,7 @@ func _update_minimap_viewport() -> void: func _update_mouse_map_position() -> void: _mouse_pos_map = _viewport_to_map_coords(_mouse_pos_viewport) - var hover_index := MapSingleton.get_province_index_from_uv_coords(_mouse_pos_map) + var hover_index := GameSingleton.get_province_index_from_uv_coords(_mouse_pos_map) if _mouse_over_viewport: _map_shader_material.set_shader_parameter(_shader_param_hover_index, hover_index) diff --git a/game/src/GameSession/ProvinceOverviewPanel.gd b/game/src/GameSession/ProvinceOverviewPanel.gd index 4615df9..832f21c 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.gd +++ b/game/src/GameSession/ProvinceOverviewPanel.gd @@ -2,32 +2,84 @@ extends Panel @export var _province_name_label : Label @export var _region_name_label : Label +@export var _buildings_container : Container -var _province_identifier: String = "": - get: return _province_identifier +const _missing_suffix : String = "_MISSING" + +var _selected_index : int: + get: return _selected_index set(v): - _province_identifier = v + _selected_index = v update_info() - -const _name_suffix : String = "_NAME" +var _province_info : Dictionary func _ready(): + GameSingleton.state_updated.connect(update_info) update_info() +enum { CANNOT_EXPAND, CAN_EXPAND, PREPARING, EXPANDING } + +func _expand_building(building_identifier : String) -> void: + if GameSingleton.expand_building(_selected_index, building_identifier) != OK: + push_error("Failed to expand ", building_identifier, " in province #", _selected_index); + +func _add_building(building : Dictionary) -> void: + const _building_key : StringName = &"building" + const _level_key : StringName = &"level" + const _expansion_state_key : StringName = &"expansion_state" + const _start_key : StringName = &"start" + const _end_key : StringName = &"end" + const _expansion_progress_key : StringName = &"expansion_progress" + + const _expand_province_building : String = "EXPAND_PROVINCE_BUILDING" + + var level_label := Label.new() + level_label.text = str(building.get(_level_key, 0)) + _buildings_container.add_child(level_label) + + var building_label := Label.new() + building_label.text = building.get(_building_key, _building_key + _missing_suffix) + _buildings_container.add_child(building_label) + + var expansion_state : int = building.get(_expansion_state_key, CANNOT_EXPAND) + if expansion_state == PREPARING or expansion_state == EXPANDING: + var progress_bar := ProgressBar.new() + progress_bar.max_value = 1 + progress_bar.value = building.get(_expansion_progress_key, 0) + progress_bar.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _buildings_container.add_child(progress_bar) + else: + var expand_button := Button.new() + expand_button.text = _expand_province_building + expand_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + expand_button.disabled = expansion_state != CAN_EXPAND + expand_button.pressed.connect(func(): _expand_building(building_label.text)) + _buildings_container.add_child(expand_button) + func update_info() -> void: - if _province_identifier: - _province_name_label.text = _province_identifier + _name_suffix - var region_identifier := MapSingleton.get_region_identifier_from_province_identifier(_province_identifier) - if region_identifier: - _region_name_label.text = region_identifier + _name_suffix - else: - _region_name_label.text = "NO REGION" + const _province_key : StringName = &"province" + const _region_key : StringName = &"region" + const _life_rating_key : StringName = &"life_rating" + const _buildings_key : StringName = &"buildings" + + _province_info = GameSingleton.get_province_info_from_index(_selected_index) + if _province_info: + _province_name_label.text = _province_info.get(_province_key, _province_key + _missing_suffix) + _region_name_label.text = _province_info.get(_region_key, _region_key + _missing_suffix) + + for child in _buildings_container.get_children(): + _buildings_container.remove_child(child) + child.queue_free() + var buildings : Array = _province_info.get(_buildings_key, []) + for building in buildings: + _add_building(building) + show() else: hide() -func _on_province_selected(identifier : String) -> void: - _province_identifier = identifier +func _on_province_selected(index : int) -> void: + _selected_index = index func _on_close_button_pressed() -> void: - _province_identifier = "" + _selected_index = 0 diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn index 7d21edc..dacdc4b 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.tscn +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] -[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label", "_region_name_label")] +[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label", "_region_name_label", "_buildings_container")] editor_description = "UI-56" anchors_preset = 2 anchor_top = 1.0 @@ -13,6 +13,7 @@ grow_vertical = 0 script = ExtResource("1_3n8k5") _province_name_label = NodePath("VBoxContainer/ProvinceName") _region_name_label = NodePath("VBoxContainer/RegionName") +_buildings_container = NodePath("VBoxContainer/BuildingsContainer") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 @@ -27,15 +28,22 @@ offset_bottom = -5.0 [node name="ProvinceName" type="Label" parent="VBoxContainer"] editor_description = "UI-57" layout_mode = 2 -text = "PROVINCE_NAME" +text = "province_MISSING" vertical_alignment = 1 [node name="RegionName" type="Label" parent="VBoxContainer"] editor_description = "UI-58" layout_mode = 2 -text = "REGION_NAME" +text = "region_MISSING" vertical_alignment = 1 +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="BuildingsContainer" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +columns = 3 + [node name="CloseButton" type="Button" parent="."] custom_minimum_size = Vector2(30, 30) layout_mode = 1 -- cgit v1.2.3-56-ga3b1 From 3d80b47304ac48018cc6ef2da557ee960e83011d Mon Sep 17 00:00:00 2001 From: ClarkeCode Date: Sun, 23 Apr 2023 19:31:57 -0400 Subject: Altering .clang-format to make compliant with clang-format 10.0.0; formerly 16.0.1 compliant --- .clang-format | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/.clang-format b/.clang-format index fff079a..8f3b82a 100644 --- a/.clang-format +++ b/.clang-format @@ -5,44 +5,31 @@ UseTab: Always TabWidth: 4 SpacesInParentheses: false SpacesInSquareBrackets: false -SpacesInLineCommentPrefix: - Minimum: 1 SpacesInContainerLiterals: false SpacesInConditionalStatement: false SpacesInCStyleCastParentheses: false -SpacesInAngles: Never +SpacesInAngles: false SpaceInEmptyParentheses: false SpaceInEmptyBlock: false SpaceBeforeSquareBrackets: false SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeParensOptions: - AfterControlStatements: true - AfterFunctionDeclarationName: false - BeforeNonEmptyParentheses: false SpaceBeforeParens: ControlStatements SpaceBeforeInheritanceColon: true SpaceBeforeCtorInitializerColon: true SpaceBeforeCpp11BracedList: true -SpaceBeforeCaseColon: false SpaceBeforeAssignmentOperators: true -SpaceAroundPointerQualifiers: Before SpaceAfterTemplateKeyword: false SpaceAfterLogicalNot: false -RemoveBracesLLVM: false -ReferenceAlignment: Left PointerAlignment: Left NamespaceIndentation: All -LineEnding: LF +IndentWidth: 4 Language: Cpp -InsertNewlineAtEOF: true -IndentExternBlock: Indent IndentCaseLabels: true FixNamespaceComments: false Cpp11BracedListStyle: false +ColumnLimit: 0 CompactNamespaces: false BreakBeforeBraces: Attach AlwaysBreakTemplateDeclarations: Yes -AlignTrailingComments: - Kind: Always +AlignTrailingComments: true AlignEscapedNewlines: Left -AlignArrayOfStructures: Right -- cgit v1.2.3-56-ga3b1 From 2c2ee99cf2d304ec28eed8560860267e95ee9017 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Fri, 21 Apr 2023 20:53:42 -0400 Subject: Refurbish UI elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move GameSession MusicPlayer to below OptionsMenu Ensures the MusicPlayer appears above the OptionsMenu Add Save and Quit/Resign to GameSessionMenu resign/quit popup To allow the player to save and resign/quit more quicker Remove GameSessionMenu hide on OptionsMenu open Renamed many UI elements to better reflect their purpose Add SessionButton theme_type_variation to GameSession buttons Add SessionButton style similar to TitleButton Disable 3D for dialog windows Change _play_pause_display_button pause text to "⏸ " Change IncreaseSpeedButton text to + Change DecreaseSpeedButton text to - Change Minimap NinePatch frame to function like a nine patch Rename actions map_zoomin and map_zoomout to map_zoom_in and map_zoom_out Change ProvinceOverviewPanel to a PanelContainer Reorganize ProvinceOverviewPanel to better use container functionality Optimize MusicPlayer Enables one line support for MusicPlayer Add warning to StyleBoxWithSound to avoid UI elements with toggle functionality --- game/localisation/en_GB/menus.csv | 2 + game/project.godot | 4 +- game/src/GameMenu.tscn | 1 - game/src/GameSession/GameSession.tscn | 24 +++---- game/src/GameSession/GameSessionMenu.gd | 48 +++++++++++++- game/src/GameSession/GameSessionMenu.tscn | 48 +++++++++----- game/src/GameSession/GameSpeedPanel.gd | 2 +- game/src/GameSession/GameSpeedPanel.tscn | 32 +++++----- game/src/GameSession/MapControlPanel.tscn | 51 ++++++++------- game/src/GameSession/MapView.gd | 8 +-- game/src/GameSession/ProvinceOverviewPanel.gd | 2 +- game/src/GameSession/ProvinceOverviewPanel.tscn | 59 ++++++++--------- game/src/MainMenu/MainMenu.tscn | 46 +++++++------- game/src/MusicConductor/MusicPlayer.tscn | 54 ++++++++-------- game/src/Utility/StyleBoxWithSound.gd | 1 + game/theme/game_session_menu.tres | 84 +++++++++++++++++++++++++ game/theme/main_menu.tres | 6 +- 17 files changed, 317 insertions(+), 155 deletions(-) create mode 100644 game/theme/game_session_menu.tres diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv index c637a39..0009acd 100644 --- a/game/localisation/en_GB/menus.csv +++ b/game/localisation/en_GB/menus.csv @@ -63,6 +63,8 @@ GAMESESSIONMENU_QUIT_DIALOG_TEXT,Are you sure you want to quit and return to des DIALOG_OK,OK DIALOG_CANCEL,Cancel +DIALOG_SAVE_AND_RESIGN,Save and Resign +DIALOG_SAVE_AND_QUIT,Save and Quit ,, Province Overview Panel province_MISSING,No Province diff --git a/game/project.godot b/game/project.godot index fa2871f..ff4081e 100644 --- a/game/project.godot +++ b/game/project.godot @@ -70,13 +70,13 @@ map_west={ , 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":65,"physical_keycode":0,"key_label":0,"unicode":97,"echo":false,"script":null) ] } -map_zoomin={ +map_zoom_in={ "deadzone": 0.5, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(174, 17),"global_position":Vector2(180, 80),"factor":1.0,"button_index":4,"pressed":true,"double_click":false,"script":null) , 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":81,"physical_keycode":0,"key_label":0,"unicode":113,"echo":false,"script":null) ] } -map_zoomout={ +map_zoom_out={ "deadzone": 0.5, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(325, 24),"global_position":Vector2(331, 87),"factor":1.0,"button_index":5,"pressed":true,"double_click":false,"script":null) , 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":69,"physical_keycode":0,"key_label":0,"unicode":101,"echo":false,"script":null) diff --git a/game/src/GameMenu.tscn b/game/src/GameMenu.tscn index aabb29c..c642351 100644 --- a/game/src/GameMenu.tscn +++ b/game/src/GameMenu.tscn @@ -43,7 +43,6 @@ anchor_left = 1.0 anchor_right = 1.0 offset_left = -184.0 offset_right = -34.0 -offset_bottom = 110.0 grow_horizontal = 0 [connection signal="credits_button_pressed" from="MainMenu" to="." method="_on_main_menu_credits_button_pressed"] diff --git a/game/src/GameSession/GameSession.tscn b/game/src/GameSession/GameSession.tscn index 8a8b18c..b993acf 100644 --- a/game/src/GameSession/GameSession.tscn +++ b/game/src/GameSession/GameSession.tscn @@ -21,15 +21,6 @@ mouse_filter = 2 script = ExtResource("1_eklvp") _game_session_menu = NodePath("GameSessionMenu") -[node name="MusicPlayer" parent="." instance=ExtResource("2_kt6aa")] -layout_mode = 1 -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -150.0 -offset_bottom = 110.0 -grow_horizontal = 0 - [node name="MapView" parent="." instance=ExtResource("4_xkg5j")] [node name="GameSessionMenu" parent="." instance=ExtResource("3_bvmqh")] @@ -56,12 +47,23 @@ grow_vertical = 0 [node name="ProvinceOverviewPanel" parent="." instance=ExtResource("5_osjnn")] layout_mode = 1 +[node name="GameSpeedPanel" parent="." instance=ExtResource("7_myy4q")] +layout_mode = 0 +offset_right = 302.0 +offset_bottom = 31.0 + [node name="OptionsMenu" parent="." instance=ExtResource("6_p5mnx")] visible = false layout_mode = 1 -[node name="GameSpeedPanel" parent="." instance=ExtResource("7_myy4q")] -layout_mode = 0 +[node name="MusicPlayer" parent="." instance=ExtResource("2_kt6aa")] +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -150.0 +offset_right = 0.0 +grow_horizontal = 0 [connection signal="map_view_camera_changed" from="MapView" to="MapControlPanel" method="_on_map_view_camera_changed"] [connection signal="province_selected" from="MapView" to="ProvinceOverviewPanel" method="_on_province_selected"] diff --git a/game/src/GameSession/GameSessionMenu.gd b/game/src/GameSession/GameSessionMenu.gd index 7d785ca..70a1630 100644 --- a/game/src/GameSession/GameSessionMenu.gd +++ b/game/src/GameSession/GameSessionMenu.gd @@ -2,8 +2,45 @@ extends PanelContainer @export var _main_menu_scene : PackedScene +@export var _main_menu_dialog : AcceptDialog +@export var _quit_dialog : AcceptDialog + +var _main_menu_save_button : Button +var _main_menu_save_separator : Control +var _quit_save_button : Button +var _quit_save_separator : Control + signal options_button_pressed +func _ready() -> void: + _main_menu_save_button = _main_menu_dialog.add_button("DIALOG_SAVE_AND_RESIGN", true, &"save_and_main_menu") + _quit_save_button = _quit_dialog.add_button("DIALOG_SAVE_AND_QUIT", true, &"save_and_quit") + + # Neccessary to center the save buttons and preserve the reference to the separator elements + var dialog_hbox : HBoxContainer = _main_menu_dialog.get_child(2, true) + var index := _main_menu_save_button.get_index(true) + dialog_hbox.move_child(_main_menu_save_button, _main_menu_dialog.get_ok_button().get_index(true)) + dialog_hbox.move_child(_main_menu_dialog.get_ok_button(), index) + _main_menu_save_separator = dialog_hbox.get_child(_main_menu_save_button.get_index(true) - 1) + + dialog_hbox = _quit_dialog.get_child(2, true) + index = _quit_save_button.get_index(true) + dialog_hbox.move_child(_quit_save_button, _quit_dialog.get_ok_button().get_index(true)) + dialog_hbox.move_child(_quit_dialog.get_ok_button(), index) + _quit_save_separator = dialog_hbox.get_child(_quit_save_button.get_index(true) - 1) + +func hide_save_dialog_button() -> void: + _main_menu_save_button.hide() + _main_menu_save_separator.hide() + _quit_save_button.hide() + _quit_save_separator.hide() + +func show_save_dialog_button() -> void: + _main_menu_save_button.show() + _main_menu_save_separator.show() + _quit_save_button.show() + _quit_save_separator.show() + # REQUIREMENTS: # * SS-47 # * UIFUN-69 @@ -21,5 +58,14 @@ func _on_quit_confirmed() -> void: # * SS-7, SS-46 # * UIFUN-11 func _on_options_button_pressed() -> void: - hide() options_button_pressed.emit() + +func _on_main_menu_dialog_custom_action(action) -> void: + match action: + &"save_and_main_menu": + _on_main_menu_confirmed() + +func _on_quit_dialog_custom_action(action : StringName) -> void: + match action: + &"save_and_quit": + _on_quit_confirmed() diff --git a/game/src/GameSession/GameSessionMenu.tscn b/game/src/GameSession/GameSessionMenu.tscn index a753184..99f38df 100644 --- a/game/src/GameSession/GameSessionMenu.tscn +++ b/game/src/GameSession/GameSessionMenu.tscn @@ -1,71 +1,89 @@ -[gd_scene load_steps=3 format=3 uid="uid://dvdynl6eir40o"] +[gd_scene load_steps=4 format=3 uid="uid://dvdynl6eir40o"] +[ext_resource type="Theme" uid="uid://dndova5cw036e" path="res://theme/game_session_menu.tres" id="1_2onog"] [ext_resource type="Script" path="res://src/GameSession/GameSessionMenu.gd" id="1_usq6o"] [ext_resource type="PackedScene" uid="uid://o4u142w4qkln" path="res://src/GameMenu.tscn" id="2_xi6a4"] -[node name="GameSessionMenu" type="PanelContainer"] +[node name="GameSessionMenu" type="PanelContainer" node_paths=PackedStringArray("_main_menu_dialog", "_quit_dialog")] +process_mode = 3 editor_description = "UI-68" +theme = ExtResource("1_2onog") +theme_type_variation = &"SessionPanel" script = ExtResource("1_usq6o") _main_menu_scene = ExtResource("2_xi6a4") +_main_menu_dialog = NodePath("MainMenuDialog") +_quit_dialog = NodePath("QuitDialog") -[node name="MarginContainer" type="MarginContainer" parent="."] +[node name="ButtonListMargin" type="MarginContainer" parent="."] layout_mode = 2 theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +[node name="ButtonList" type="VBoxContainer" parent="ButtonListMargin"] layout_mode = 2 -[node name="SaveButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="SaveButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "UI-69" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_SAVE" -[node name="LoadButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="LoadButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "UI-70" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_LOAD" -[node name="OptionsButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="OptionsButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "UI-10" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_OPTIONS" -[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="MainMenuButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "UI-71" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_MAINMENU" -[node name="QuitButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="QuitButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "UI-72" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_QUIT" -[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"] +[node name="CloseSeparator" type="HSeparator" parent="ButtonListMargin/ButtonList"] layout_mode = 2 +theme_type_variation = &"SessionSeparator" -[node name="CloseButton" type="Button" parent="MarginContainer/VBoxContainer"] +[node name="CloseButton" type="Button" parent="ButtonListMargin/ButtonList"] editor_description = "SS-64, UI-80, UIFUN-79" layout_mode = 2 +theme_type_variation = &"SessionButton" text = "GAMESESSIONMENU_CLOSE" [node name="MainMenuDialog" type="ConfirmationDialog" parent="."] +disable_3d = true title = "GAMESESSIONMENU_MAINMENU_DIALOG_TITLE" +size = Vector2i(384, 100) ok_button_text = "DIALOG_OK" dialog_text = "GAMESESSIONMENU_MAINMENU_DIALOG_TEXT" cancel_button_text = "DIALOG_CANCEL" [node name="QuitDialog" type="ConfirmationDialog" parent="."] +disable_3d = true title = "GAMESESSIONMENU_QUIT_DIALOG_TITLE" ok_button_text = "DIALOG_OK" dialog_text = "GAMESESSIONMENU_QUIT_DIALOG_TEXT" cancel_button_text = "DIALOG_CANCEL" -[connection signal="pressed" from="MarginContainer/VBoxContainer/OptionsButton" to="." method="_on_options_button_pressed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="MainMenuDialog" method="popup_centered"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/QuitButton" to="QuitDialog" method="popup_centered"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/CloseButton" to="." method="hide"] +[connection signal="pressed" from="ButtonListMargin/ButtonList/OptionsButton" to="." method="_on_options_button_pressed"] +[connection signal="pressed" from="ButtonListMargin/ButtonList/MainMenuButton" to="MainMenuDialog" method="popup_centered"] +[connection signal="pressed" from="ButtonListMargin/ButtonList/QuitButton" to="QuitDialog" method="popup_centered"] +[connection signal="pressed" from="ButtonListMargin/ButtonList/CloseButton" to="." method="hide"] [connection signal="confirmed" from="MainMenuDialog" to="." method="_on_main_menu_confirmed"] +[connection signal="custom_action" from="MainMenuDialog" to="." method="_on_main_menu_dialog_custom_action"] [connection signal="confirmed" from="QuitDialog" to="." method="_on_quit_confirmed"] +[connection signal="custom_action" from="QuitDialog" to="." method="_on_quit_dialog_custom_action"] diff --git a/game/src/GameSession/GameSpeedPanel.gd b/game/src/GameSession/GameSpeedPanel.gd index c203032..8b7af29 100644 --- a/game/src/GameSession/GameSpeedPanel.gd +++ b/game/src/GameSession/GameSpeedPanel.gd @@ -13,7 +13,7 @@ func _ready(): _update_buttons() func _update_buttons(): - _play_pause_display_button.text = "⏸️" if GameSingleton.is_paused() else "▶" + _play_pause_display_button.text = "⏸ " if GameSingleton.is_paused() else "▶" _increase_speed_button.disabled = not GameSingleton.can_increase_speed() _decrease_speed_button.disabled = not GameSingleton.can_decrease_speed() diff --git a/game/src/GameSession/GameSpeedPanel.tscn b/game/src/GameSession/GameSpeedPanel.tscn index bfb869c..8a37565 100644 --- a/game/src/GameSession/GameSpeedPanel.tscn +++ b/game/src/GameSession/GameSpeedPanel.tscn @@ -4,35 +4,35 @@ [node name="GameSpeedPanel" type="PanelContainer" node_paths=PackedStringArray("_longform_date_button", "_play_pause_display_button", "_decrease_speed_button", "_increase_speed_button")] script = ExtResource("1_pfs8t") -_longform_date_button = NodePath("HBoxContainer/LongformDateButton") -_play_pause_display_button = NodePath("HBoxContainer/PlayPauseDisplayButton") -_decrease_speed_button = NodePath("HBoxContainer/DecreaseSpeedButton") -_increase_speed_button = NodePath("HBoxContainer/IncreaseSpeedButton") +_longform_date_button = NodePath("ButtonList/LongformDateButton") +_play_pause_display_button = NodePath("ButtonList/PlayPauseDisplayButton") +_decrease_speed_button = NodePath("ButtonList/DecreaseSpeedButton") +_increase_speed_button = NodePath("ButtonList/IncreaseSpeedButton") -[node name="HBoxContainer" type="HBoxContainer" parent="."] +[node name="ButtonList" type="HBoxContainer" parent="."] layout_mode = 2 -[node name="LongformDateButton" type="Button" parent="HBoxContainer"] +[node name="LongformDateButton" type="Button" parent="ButtonList"] custom_minimum_size = Vector2(200, 0) layout_mode = 2 text = "LONGFORM DATE" -[node name="PlayPauseDisplayButton" type="Button" parent="HBoxContainer"] +[node name="PlayPauseDisplayButton" type="Button" parent="ButtonList"] custom_minimum_size = Vector2(30, 0) layout_mode = 2 -text = "⏸" +text = "⏸ " -[node name="DecreaseSpeedButton" type="Button" parent="HBoxContainer"] +[node name="DecreaseSpeedButton" type="Button" parent="ButtonList"] custom_minimum_size = Vector2(30, 0) layout_mode = 2 -text = "➖" +text = "-" -[node name="IncreaseSpeedButton" type="Button" parent="HBoxContainer"] +[node name="IncreaseSpeedButton" type="Button" parent="ButtonList"] custom_minimum_size = Vector2(30, 0) layout_mode = 2 -text = "➕" +text = "+" -[connection signal="pressed" from="HBoxContainer/LongformDateButton" to="." method="_on_longform_date_label_pressed"] -[connection signal="pressed" from="HBoxContainer/PlayPauseDisplayButton" to="." method="_on_play_pause_display_button_pressed"] -[connection signal="pressed" from="HBoxContainer/DecreaseSpeedButton" to="." method="_on_decrease_speed_button_pressed"] -[connection signal="pressed" from="HBoxContainer/IncreaseSpeedButton" to="." method="_on_increase_speed_button_pressed"] +[connection signal="pressed" from="ButtonList/LongformDateButton" to="." method="_on_longform_date_label_pressed"] +[connection signal="pressed" from="ButtonList/PlayPauseDisplayButton" to="." method="_on_play_pause_display_button_pressed"] +[connection signal="pressed" from="ButtonList/DecreaseSpeedButton" to="." method="_on_decrease_speed_button_pressed"] +[connection signal="pressed" from="ButtonList/IncreaseSpeedButton" to="." method="_on_increase_speed_button_pressed"] diff --git a/game/src/GameSession/MapControlPanel.tscn b/game/src/GameSession/MapControlPanel.tscn index 27205e3..18b1c3f 100644 --- a/game/src/GameSession/MapControlPanel.tscn +++ b/game/src/GameSession/MapControlPanel.tscn @@ -15,89 +15,96 @@ events = [SubResource("InputEventAction_5nck3")] editor_description = "SS-103" mouse_filter = 1 script = ExtResource("1_ign64") -_mapmodes_grid = NodePath("MarginContainer/HBoxContainer/VBoxContainer/MapmodesGrid") +_mapmodes_grid = NodePath("MapPanelMargin/MapPanelList/MapDisplayList/MapmodesGrid") -[node name="MarginContainer" type="MarginContainer" parent="."] +[node name="MapPanelMargin" type="MarginContainer" parent="."] layout_mode = 2 theme_override_constants/margin_left = 5 theme_override_constants/margin_top = 5 theme_override_constants/margin_right = 5 theme_override_constants/margin_bottom = 5 -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] +[node name="MapPanelList" type="HBoxContainer" parent="MapPanelMargin"] layout_mode = 2 theme_override_constants/separation = 6 alignment = 1 -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] +[node name="MapDisplayList" type="VBoxContainer" parent="MapPanelMargin/MapPanelList"] layout_mode = 2 alignment = 1 -[node name="MapmodesGrid" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] +[node name="MapmodesGrid" type="GridContainer" parent="MapPanelMargin/MapPanelList/MapDisplayList"] editor_description = "UI-750" layout_mode = 2 columns = 11 -[node name="Minimap" type="PanelContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] +[node name="Minimap" type="PanelContainer" parent="MapPanelMargin/MapPanelList/MapDisplayList"] editor_description = "UI-549" layout_mode = 2 mouse_filter = 1 -[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] +[node name="MinimapTexture" type="TextureRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] editor_description = "UI-751, FS-338" layout_mode = 2 texture = ExtResource("2_r613r") -[node name="ViewportQuad" type="Control" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] +[node name="ViewportQuad" type="Control" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] layout_mode = 2 mouse_filter = 2 script = ExtResource("3_s4dml") -[node name="Frame" type="NinePatchRect" parent="MarginContainer/HBoxContainer/VBoxContainer/Minimap"] +[node name="Frame" type="NinePatchRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"] layout_mode = 2 texture = ExtResource("4_f1exl") - -[node name="AuxiliaryPanel" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] +draw_center = false +patch_margin_left = 10 +patch_margin_top = 10 +patch_margin_right = 10 +patch_margin_bottom = 10 +axis_stretch_horizontal = 1 +axis_stretch_vertical = 1 + +[node name="AuxiliaryPanel" type="VBoxContainer" parent="MapPanelMargin/MapPanelList"] editor_description = "UI-761" layout_mode = 2 -[node name="GameSessionMenuButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +[node name="GameSessionMenuButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] editor_description = "UI-9" layout_mode = 2 mouse_filter = 1 shortcut = SubResource("Shortcut_fc1tk") text = "ESC" -[node name="LedgerButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +[node name="LedgerButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] editor_description = "UI-860" layout_mode = 2 mouse_filter = 1 text = "L" -[node name="FindButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +[node name="FindButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] editor_description = "UI-861" layout_mode = 2 mouse_filter = 1 text = "F" -[node name="ZoomButtonsContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/AuxiliaryPanel"] +[node name="ZoomButtonsContainer" type="HBoxContainer" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] layout_mode = 2 alignment = 1 -[node name="ZoomInButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer"] +[node name="ZoomInButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer"] editor_description = "UI-862" layout_mode = 2 mouse_filter = 1 text = "+" -[node name="ZoomOutButton" type="Button" parent="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer"] +[node name="ZoomOutButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer"] editor_description = "UI-863" layout_mode = 2 mouse_filter = 1 text = "-" -[connection signal="map_view_camera_changed" from="." to="MarginContainer/HBoxContainer/VBoxContainer/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] -[connection signal="minimap_clicked" from="MarginContainer/HBoxContainer/VBoxContainer/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] -[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] -[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer/ZoomInButton" to="." method="_on_zoom_in_button_pressed"] -[connection signal="pressed" from="MarginContainer/HBoxContainer/AuxiliaryPanel/ZoomButtonsContainer/ZoomOutButton" to="." method="_on_zoom_out_button_pressed"] +[connection signal="map_view_camera_changed" from="." to="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] +[connection signal="minimap_clicked" from="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] +[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] +[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomInButton" to="." method="_on_zoom_in_button_pressed"] +[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomOutButton" to="." method="_on_zoom_out_button_pressed"] diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index ac060e1..510d70a 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -7,8 +7,8 @@ const _action_north : StringName = &"map_north" const _action_east : StringName = &"map_east" const _action_south : StringName = &"map_south" const _action_west : StringName = &"map_west" -const _action_zoomin : StringName = &"map_zoomin" -const _action_zoomout : StringName = &"map_zoomout" +const _action_zoom_in : StringName = &"map_zoom_in" +const _action_zoom_out : StringName = &"map_zoom_out" const _action_drag : StringName = &"map_drag" const _action_click : StringName = &"map_click" @@ -165,9 +165,9 @@ func _unhandled_input(event : InputEvent): if not _drag_active: push_warning("Drag being deactivated while already not active!") _drag_active = false - elif event.is_action_pressed(_action_zoomin, true): + elif event.is_action_pressed(_action_zoom_in, true): zoom_in() - elif event.is_action_pressed(_action_zoomout, true): + elif event.is_action_pressed(_action_zoom_out, true): zoom_out() func _physics_process(delta : float): diff --git a/game/src/GameSession/ProvinceOverviewPanel.gd b/game/src/GameSession/ProvinceOverviewPanel.gd index 832f21c..cbab9d0 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.gd +++ b/game/src/GameSession/ProvinceOverviewPanel.gd @@ -1,4 +1,4 @@ -extends Panel +extends PanelContainer @export var _province_name_label : Label @export var _region_name_label : Label diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn index dacdc4b..7b28cc1 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.tscn +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] -[node name="ProvinceOverviewPanel" type="Panel" node_paths=PackedStringArray("_province_name_label", "_region_name_label", "_buildings_container")] +[node name="ProvinceOverviewPanel" type="PanelContainer" node_paths=PackedStringArray("_province_name_label", "_region_name_label", "_buildings_container")] editor_description = "UI-56" anchors_preset = 2 anchor_top = 1.0 @@ -11,47 +11,48 @@ offset_top = -300.0 offset_right = 200.0 grow_vertical = 0 script = ExtResource("1_3n8k5") -_province_name_label = NodePath("VBoxContainer/ProvinceName") -_region_name_label = NodePath("VBoxContainer/RegionName") -_buildings_container = NodePath("VBoxContainer/BuildingsContainer") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = -1 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 10.0 -offset_top = 5.0 -offset_right = -10.0 -offset_bottom = -5.0 +_province_name_label = NodePath("PanelList/TopBarList/NameList/ProvinceName") +_region_name_label = NodePath("PanelList/TopBarList/NameList/RegionName") +_buildings_container = NodePath("PanelList/InteractList/BuildingsContainer") + +[node name="PanelList" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="TopBarList" type="HBoxContainer" parent="PanelList"] +layout_mode = 2 + +[node name="NameList" type="VBoxContainer" parent="PanelList/TopBarList"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 -[node name="ProvinceName" type="Label" parent="VBoxContainer"] +[node name="ProvinceName" type="Label" parent="PanelList/TopBarList/NameList"] editor_description = "UI-57" layout_mode = 2 text = "province_MISSING" vertical_alignment = 1 -[node name="RegionName" type="Label" parent="VBoxContainer"] +[node name="RegionName" type="Label" parent="PanelList/TopBarList/NameList"] editor_description = "UI-58" layout_mode = 2 text = "region_MISSING" vertical_alignment = 1 -[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +[node name="CloseButton" type="Button" parent="PanelList/TopBarList"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +size_flags_vertical = 0 +text = "X" + +[node name="InteractList" type="VBoxContainer" parent="PanelList"] layout_mode = 2 +size_flags_vertical = 3 -[node name="BuildingsContainer" type="GridContainer" parent="VBoxContainer"] +[node name="HSeparator" type="HSeparator" parent="PanelList/InteractList"] layout_mode = 2 -columns = 3 -[node name="CloseButton" type="Button" parent="."] -custom_minimum_size = Vector2(30, 30) -layout_mode = 1 -anchors_preset = -1 -anchor_left = 0.85 -anchor_right = 1.0 -anchor_bottom = 0.103333 -grow_horizontal = 0 -text = "X" +[node name="BuildingsContainer" type="GridContainer" parent="PanelList/InteractList"] +layout_mode = 2 +columns = 3 -[connection signal="pressed" from="CloseButton" to="." method="_on_close_button_pressed"] +[connection signal="pressed" from="PanelList/TopBarList/CloseButton" to="." method="_on_close_button_pressed"] diff --git a/game/src/MainMenu/MainMenu.tscn b/game/src/MainMenu/MainMenu.tscn index a10fa27..0618fe8 100644 --- a/game/src/MainMenu/MainMenu.tscn +++ b/game/src/MainMenu/MainMenu.tscn @@ -16,9 +16,9 @@ grow_horizontal = 2 grow_vertical = 2 theme = ExtResource("1_1yri4") script = ExtResource("2_nm1fq") -_new_game_button = NodePath("Panel/VBox/Margin/ButtonList/NewGameButton") +_new_game_button = NodePath("MenuPanel/MenuList/ButtonListMargin/ButtonList/NewGameButton") -[node name="Panel" type="PanelContainer" parent="."] +[node name="MenuPanel" type="PanelContainer" parent="."] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -27,10 +27,10 @@ grow_horizontal = 2 grow_vertical = 2 theme_type_variation = &"BackgroundPanel" -[node name="VBox" type="VBoxContainer" parent="Panel"] +[node name="MenuList" type="VBoxContainer" parent="MenuPanel"] layout_mode = 2 -[node name="TextureRect" type="TextureRect" parent="Panel/VBox"] +[node name="TitleIcon" type="TextureRect" parent="MenuPanel/MenuList"] layout_mode = 2 size_flags_vertical = 3 size_flags_stretch_ratio = 1.75 @@ -38,19 +38,19 @@ texture = ExtResource("3_58ess") expand_mode = 1 stretch_mode = 5 -[node name="Margin" type="MarginContainer" parent="Panel/VBox"] +[node name="ButtonListMargin" type="MarginContainer" parent="MenuPanel/MenuList"] layout_mode = 2 theme_override_constants/margin_left = 15 theme_override_constants/margin_right = 12 -[node name="ButtonList" type="HBoxContainer" parent="Panel/VBox/Margin"] +[node name="ButtonList" type="HBoxContainer" parent="MenuPanel/MenuList/ButtonListMargin"] custom_minimum_size = Vector2(500, 0) layout_mode = 2 theme_type_variation = &"HBox_MainMenu_ButtonList" theme_override_constants/separation = 18 alignment = 1 -[node name="NewGameButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="NewGameButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] editor_description = "UI-26" layout_mode = 2 size_flags_horizontal = 3 @@ -63,7 +63,7 @@ theme_type_variation = &"TitleButton" text = "MAINMENU_NEW_GAME" clip_text = true -[node name="ContinueButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="ContinueButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] layout_mode = 2 size_flags_horizontal = 3 focus_neighbor_left = NodePath("../NewGameButton") @@ -75,7 +75,7 @@ disabled = true text = "MAINMENU_CONTINUE" clip_text = true -[node name="MultiplayerButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="MultiplayerButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] editor_description = "UI-27" layout_mode = 2 size_flags_horizontal = 3 @@ -87,7 +87,7 @@ theme_type_variation = &"TitleButton" text = "MAINMENU_MULTIPLAYER" clip_text = true -[node name="OptionsButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="OptionsButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] editor_description = "UI-5" layout_mode = 2 size_flags_horizontal = 3 @@ -99,7 +99,7 @@ theme_type_variation = &"TitleButton" text = "MAINMENU_OPTIONS" clip_text = true -[node name="CreditsButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="CreditsButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] editor_description = "UI-32" layout_mode = 2 size_flags_horizontal = 3 @@ -111,7 +111,7 @@ theme_type_variation = &"TitleButton" text = "MAINMENU_CREDITS" clip_text = true -[node name="ExitButton" type="Button" parent="Panel/VBox/Margin/ButtonList"] +[node name="ExitButton" type="Button" parent="MenuPanel/MenuList/ButtonListMargin/ButtonList"] editor_description = "UI-3" layout_mode = 2 size_flags_horizontal = 3 @@ -123,28 +123,28 @@ theme_type_variation = &"TitleButton" text = "MAINMENU_EXIT" clip_text = true -[node name="BottomSpace" type="Control" parent="Panel/VBox"] +[node name="BottomSpace" type="Control" parent="MenuPanel/MenuList"] layout_mode = 2 size_flags_vertical = 3 size_flags_stretch_ratio = 0.35 -[node name="BottomMargin" type="MarginContainer" parent="Panel/VBox"] +[node name="BottomMargin" type="MarginContainer" parent="MenuPanel/MenuList"] layout_mode = 2 theme_type_variation = &"BottomMargin" -[node name="ReleaseInfoBox" parent="Panel/VBox/BottomMargin" instance=ExtResource("3_km0er")] +[node name="ReleaseInfoBox" parent="MenuPanel/MenuList/BottomMargin" instance=ExtResource("3_km0er")] layout_mode = 2 -[node name="LocaleButton" parent="Panel/VBox/BottomMargin" instance=ExtResource("3_amonp")] +[node name="LocaleButton" parent="MenuPanel/MenuList/BottomMargin" instance=ExtResource("3_amonp")] layout_mode = 2 size_flags_horizontal = 8 alignment = 0 text_overrun_behavior = 4 -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/NewGameButton" to="." method="_on_new_game_button_pressed"] -[connection signal="visibility_changed" from="Panel/VBox/Margin/ButtonList/NewGameButton" to="." method="_on_new_game_button_visibility_changed"] -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/ContinueButton" to="." method="_on_continue_button_pressed"] -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/MultiplayerButton" to="." method="_on_multi_player_button_pressed"] -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/OptionsButton" to="." method="_on_options_button_pressed"] -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/CreditsButton" to="." method="_on_credits_button_pressed"] -[connection signal="pressed" from="Panel/VBox/Margin/ButtonList/ExitButton" to="." method="_on_exit_button_pressed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/NewGameButton" to="." method="_on_new_game_button_pressed"] +[connection signal="visibility_changed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/NewGameButton" to="." method="_on_new_game_button_visibility_changed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/ContinueButton" to="." method="_on_continue_button_pressed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/MultiplayerButton" to="." method="_on_multi_player_button_pressed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/OptionsButton" to="." method="_on_options_button_pressed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/CreditsButton" to="." method="_on_credits_button_pressed"] +[connection signal="pressed" from="MenuPanel/MenuList/ButtonListMargin/ButtonList/ExitButton" to="." method="_on_exit_button_pressed"] diff --git a/game/src/MusicConductor/MusicPlayer.tscn b/game/src/MusicConductor/MusicPlayer.tscn index 91b6fd3..80ad641 100644 --- a/game/src/MusicConductor/MusicPlayer.tscn +++ b/game/src/MusicConductor/MusicPlayer.tscn @@ -4,58 +4,60 @@ [node name="MusicPlayer" type="BoxContainer" node_paths=PackedStringArray("_song_selector_button", "_progress_slider", "_previous_song_button", "_play_pause_button", "_next_song_button", "_visbility_button")] editor_description = "UI-104" +offset_right = 150.0 +offset_bottom = 110.0 mouse_filter = 2 +vertical = true script = ExtResource("1_gcm4m") -_song_selector_button = NodePath("Control/SongSelectorButton") -_progress_slider = NodePath("Control/ProgressSlider") -_previous_song_button = NodePath("Control/HBoxContainer/PreviousSongButton") -_play_pause_button = NodePath("Control/HBoxContainer/PlayPauseButton") -_next_song_button = NodePath("Control/HBoxContainer/NextSongButton") -_visbility_button = NodePath("Control/MusicUIVisibilityButton") - -[node name="Control" type="VBoxContainer" parent="."] -custom_minimum_size = Vector2(150, 0) -layout_mode = 2 -mouse_filter = 2 - -[node name="SongSelectorButton" type="OptionButton" parent="Control"] +_song_selector_button = NodePath("SongSelectorButton") +_progress_slider = NodePath("ProgressSlider") +_previous_song_button = NodePath("ButtonList/PreviousSongButton") +_play_pause_button = NodePath("ButtonList/PlayPauseButton") +_next_song_button = NodePath("ButtonList/NextSongButton") +_visbility_button = NodePath("MusicUIVisibilityButton") + +[node name="SongSelectorButton" type="OptionButton" parent="."] editor_description = "UI-107" +custom_minimum_size = Vector2(150, 0) layout_mode = 2 alignment = 1 text_overrun_behavior = 3 fit_to_longest_item = false -[node name="ProgressSlider" type="HSlider" parent="Control"] +[node name="ProgressSlider" type="HSlider" parent="."] +custom_minimum_size = Vector2(150, 0) layout_mode = 2 +size_flags_vertical = 1 -[node name="HBoxContainer" type="HBoxContainer" parent="Control"] +[node name="ButtonList" type="HBoxContainer" parent="."] layout_mode = 2 size_flags_horizontal = 4 mouse_filter = 2 -[node name="PreviousSongButton" type="Button" parent="Control/HBoxContainer"] +[node name="PreviousSongButton" type="Button" parent="ButtonList"] layout_mode = 2 text = "<" -[node name="PlayPauseButton" type="Button" parent="Control/HBoxContainer"] +[node name="PlayPauseButton" type="Button" parent="ButtonList"] custom_minimum_size = Vector2(30, 0) layout_mode = 2 text = "▶" -[node name="NextSongButton" type="Button" parent="Control/HBoxContainer"] +[node name="NextSongButton" type="Button" parent="ButtonList"] layout_mode = 2 text = ">" -[node name="MusicUIVisibilityButton" type="Button" parent="Control"] +[node name="MusicUIVisibilityButton" type="Button" parent="."] editor_description = "UI-106" layout_mode = 2 size_flags_horizontal = 4 +toggle_mode = true text = "⬆" -[connection signal="item_selected" from="Control/SongSelectorButton" to="." method="_on_option_button_item_selected"] -[connection signal="drag_ended" from="Control/ProgressSlider" to="." method="_on_progress_slider_drag_ended"] -[connection signal="drag_started" from="Control/ProgressSlider" to="." method="_on_progress_slider_drag_started"] -[connection signal="pressed" from="Control/HBoxContainer/PreviousSongButton" to="." method="_on_previous_song_button_pressed"] -[connection signal="pressed" from="Control/HBoxContainer/PlayPauseButton" to="." method="_on_play_pause_button_pressed"] -[connection signal="pressed" from="Control/HBoxContainer/NextSongButton" to="." method="_on_next_song_button_pressed"] -[connection signal="pressed" from="Control/MusicUIVisibilityButton" to="." method="_on_music_ui_visibility_button_pressed"] +[connection signal="item_selected" from="SongSelectorButton" to="." method="_on_option_button_item_selected"] +[connection signal="drag_ended" from="ProgressSlider" to="." method="_on_progress_slider_drag_ended"] +[connection signal="drag_started" from="ProgressSlider" to="." method="_on_progress_slider_drag_started"] +[connection signal="pressed" from="ButtonList/PreviousSongButton" to="." method="_on_previous_song_button_pressed"] +[connection signal="pressed" from="ButtonList/PlayPauseButton" to="." method="_on_play_pause_button_pressed"] +[connection signal="pressed" from="ButtonList/NextSongButton" to="." method="_on_next_song_button_pressed"] +[connection signal="pressed" from="MusicUIVisibilityButton" to="." method="_on_music_ui_visibility_button_pressed"] diff --git a/game/src/Utility/StyleBoxWithSound.gd b/game/src/Utility/StyleBoxWithSound.gd index 8de1af1..8c29b34 100644 --- a/game/src/Utility/StyleBoxWithSound.gd +++ b/game/src/Utility/StyleBoxWithSound.gd @@ -1,3 +1,4 @@ +## WARNING: This will not work with togglable UI elements, a special implementation is needed for them. @tool extends StyleBox class_name StyleBoxWithSound diff --git a/game/theme/game_session_menu.tres b/game/theme/game_session_menu.tres new file mode 100644 index 0000000..42775c3 --- /dev/null +++ b/game/theme/game_session_menu.tres @@ -0,0 +1,84 @@ +[gd_resource type="Theme" load_steps=11 format=3 uid="uid://dndova5cw036e"] + +[ext_resource type="StyleBox" uid="uid://blwilunhmyvpq" path="res://theme/assets/main_menu_button_normal.tres" id="1_7med2"] +[ext_resource type="Script" path="res://src/Utility/StyleBoxWithSound.gd" id="2_oj3dv"] +[ext_resource type="AudioStream" uid="uid://bsldcs3l8s7ug" path="res://addons/kenney_ui_audio/click3.wav" id="3_j823n"] +[ext_resource type="Texture2D" uid="uid://c0p34i3d3b0pw" path="res://theme/assets/main_menu_button.png" id="4_lno5s"] + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_jvvyi"] +content_margin_left = 20.0 +content_margin_top = 10.0 +content_margin_right = 20.0 +content_margin_bottom = 14.0 +texture = ExtResource("4_lno5s") +modulate_color = Color(0.817521, 0.817521, 0.817521, 0.784314) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6ab1x"] +draw_center = false +border_width_left = 10 +border_width_top = 15 +border_width_right = 10 +border_width_bottom = 15 +border_color = Color(0, 0, 0, 0.584314) +border_blend = true +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 +corner_detail = 20 + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_jslj0"] +content_margin_left = 20.0 +content_margin_top = 10.0 +content_margin_right = 20.0 +content_margin_bottom = 14.0 +texture = ExtResource("4_lno5s") +modulate_color = Color(0.588235, 0.588235, 0.588235, 1) + +[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_l2rw3"] +content_margin_left = 20.0 +content_margin_top = 10.0 +content_margin_right = 20.0 +content_margin_bottom = 14.0 +texture = ExtResource("4_lno5s") +modulate_color = Color(0.85098, 0.85098, 0.85098, 1) + +[sub_resource type="StyleBox" id="StyleBox_ptkcj"] +resource_local_to_scene = false +resource_name = "" +content_margin_left = -1.0 +content_margin_top = -1.0 +content_margin_right = -1.0 +content_margin_bottom = -1.0 +script = ExtResource("2_oj3dv") +style_box = SubResource("StyleBoxTexture_l2rw3") +sound = ExtResource("3_j823n") + +[sub_resource type="StyleBoxLine" id="StyleBoxLine_kaw4i"] +color = Color(0.454902, 0.45098, 0.435294, 1) +thickness = 2 + +[resource] +SessionButton/base_type = &"Button" +SessionButton/colors/font_color = Color(0.87451, 0.87451, 0.87451, 1) +SessionButton/colors/font_disabled_color = Color(0.87451, 0.87451, 0.87451, 0.501961) +SessionButton/colors/font_focus_color = Color(0.94902, 0.94902, 0.94902, 1) +SessionButton/colors/font_hover_color = Color(0.94902, 0.94902, 0.94902, 1) +SessionButton/colors/font_hover_pressed_color = Color(1, 1, 1, 1) +SessionButton/colors/font_outline_color = Color(1, 1, 1, 1) +SessionButton/colors/font_pressed_color = Color(1, 1, 1, 1) +SessionButton/colors/icon_disabled_color = Color(1, 1, 1, 0.4) +SessionButton/colors/icon_focus_color = Color(0.94902, 0.94902, 0.94902, 1) +SessionButton/colors/icon_hover_color = Color(0.94902, 0.94902, 0.94902, 1) +SessionButton/colors/icon_hover_pressed_color = Color(1, 1, 1, 1) +SessionButton/colors/icon_normal_color = Color(1, 1, 1, 1) +SessionButton/colors/icon_pressed_color = Color(1, 1, 1, 1) +SessionButton/styles/disabled = SubResource("StyleBoxTexture_jvvyi") +SessionButton/styles/focus = SubResource("StyleBoxFlat_6ab1x") +SessionButton/styles/hover = SubResource("StyleBoxTexture_jslj0") +SessionButton/styles/normal = ExtResource("1_7med2") +SessionButton/styles/pressed = SubResource("StyleBox_ptkcj") +SessionPanel/base_type = &"Panel" +SessionPanel/styles/panel = null +SessionSeparator/base_type = &"HSeparator" +SessionSeparator/styles/separator = SubResource("StyleBoxLine_kaw4i") diff --git a/game/theme/main_menu.tres b/game/theme/main_menu.tres index 6a3f73d..0518cd8 100644 --- a/game/theme/main_menu.tres +++ b/game/theme/main_menu.tres @@ -171,9 +171,9 @@ CommitLabel/styles/normal = SubResource("StyleBoxEmpty_kmfi1") CommitLabel/styles/pressed = SubResource("StyleBoxEmpty_1qcrh") TitleButton/base_type = &"Button" TitleButton/colors/font_color = Color(0.87451, 0.87451, 0.87451, 1) -TitleButton/colors/font_disabled_color = Color(0.875, 0.875, 0.875, 0.5) -TitleButton/colors/font_focus_color = Color(0.95, 0.95, 0.95, 1) -TitleButton/colors/font_hover_color = Color(0.95, 0.95, 0.95, 1) +TitleButton/colors/font_disabled_color = Color(0.87451, 0.87451, 0.87451, 0.501961) +TitleButton/colors/font_focus_color = Color(0.94902, 0.94902, 0.94902, 1) +TitleButton/colors/font_hover_color = Color(0.94902, 0.94902, 0.94902, 1) TitleButton/colors/font_hover_pressed_color = Color(1, 1, 1, 1) TitleButton/colors/font_outline_color = Color(1, 1, 1, 1) TitleButton/colors/font_pressed_color = Color(1, 1, 1, 1) -- cgit v1.2.3-56-ga3b1 From 8fba1c8a02f8680e0d80279b8b6451fea4a40a62 Mon Sep 17 00:00:00 2001 From: Hop311 Date: Tue, 25 Apr 2023 00:03:15 +0100 Subject: Req comments + cleanup + c++ registry refactoring --- extension/src/GameSingleton.cpp | 4 +- extension/src/openvic2/Logger.cpp | 4 +- extension/src/openvic2/Logger.hpp | 6 +- extension/src/openvic2/Types.hpp | 62 +++++++++++ extension/src/openvic2/map/Building.cpp | 34 ++---- extension/src/openvic2/map/Building.hpp | 11 +- extension/src/openvic2/map/Map.cpp | 139 ++++++++---------------- extension/src/openvic2/map/Map.hpp | 12 +- extension/src/openvic2/map/Province.cpp | 15 +-- extension/src/openvic2/map/Province.hpp | 3 +- game/localisation/en_GB/menus.csv | 1 + game/src/GameSession/GameSpeedPanel.gd | 1 - game/src/GameSession/ProvinceOverviewPanel.gd | 10 ++ game/src/GameSession/ProvinceOverviewPanel.tscn | 7 +- 14 files changed, 165 insertions(+), 144 deletions(-) diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp index 68eb252..f596cc2 100644 --- a/extension/src/GameSingleton.cpp +++ b/extension/src/GameSingleton.cpp @@ -79,6 +79,7 @@ GameSingleton::GameSingleton() : game_manager{ [this]() { emit_signal("state_upd }; for (mapmode_t const& mapmode : mapmodes) game_manager.map.add_mapmode(mapmode.first, mapmode.second); + game_manager.map.lock_mapmodes(); using building_type_t = std::tuple; const std::vector building_types = { @@ -86,6 +87,7 @@ GameSingleton::GameSingleton() : game_manager{ [this]() { emit_signal("state_upd }; for (building_type_t const& type : building_types) game_manager.building_manager.add_building_type(std::get<0>(type), std::get<1>(type), std::get<2>(type)); + game_manager.building_manager.lock_building_types(); } @@ -332,7 +334,7 @@ Dictionary GameSingleton::get_province_info_from_index(int32_t index) const { Dictionary building_dict; Building const& building = buildings[idx]; - building_dict[building_key] = building.get_type().get_identifier().c_str(); + building_dict[building_key] = building.get_identifier().c_str(); building_dict[level_key] = static_cast(building.get_level()); building_dict[expansion_state_key] = static_cast(building.get_expansion_state()); building_dict[start_date_key] = static_cast(building.get_start_date()).c_str(); diff --git a/extension/src/openvic2/Logger.cpp b/extension/src/openvic2/Logger.cpp index f211e7e..56d74ab 100644 --- a/extension/src/openvic2/Logger.cpp +++ b/extension/src/openvic2/Logger.cpp @@ -7,9 +7,9 @@ using namespace OpenVic2; Logger::log_func_t Logger::info_func = [](std::string&& str) { std::cout << str; }; Logger::log_func_t Logger::error_func = [](std::string&& str) { std::cerr << str; }; -const char* Logger::get_filename(const char* filepath) { +char const* Logger::get_filename(char const* filepath) { if (filepath == nullptr) return nullptr; - const char *last_slash = filepath; + char const* last_slash = filepath; while (*filepath != '\0') { if (*filepath == '\\' || *filepath == '/') last_slash = filepath + 1; filepath++; diff --git a/extension/src/openvic2/Logger.hpp b/extension/src/openvic2/Logger.hpp index 749c67f..624df29 100644 --- a/extension/src/openvic2/Logger.hpp +++ b/extension/src/openvic2/Logger.hpp @@ -25,9 +25,9 @@ namespace OpenVic2 { return source_location(f, l, n); } - inline const char* file_name() const { return _file.c_str(); } + inline char const* file_name() const { return _file.c_str(); } inline int line() const {return _line; } - inline const char* function_name() const { return _function.c_str(); } + inline char const* function_name() const { return _function.c_str(); } }; #endif @@ -42,7 +42,7 @@ namespace OpenVic2 { static log_func_t info_func, error_func; - static const char* get_filename(const char* filepath); + static char const* get_filename(char const* filepath); template struct log { diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp index b20db10..226dd30 100644 --- a/extension/src/openvic2/Types.hpp +++ b/extension/src/openvic2/Types.hpp @@ -17,4 +17,66 @@ namespace OpenVic2 { public: std::string const& get_identifier() const; }; + + template::value>::type* = nullptr> + class IdentifierRegistry { + std::vector items; + bool locked = false; + public: + return_t add_item(T&& item) { + if (locked) { + Logger::error("Cannot add item to the ", name, " registry - locked!"); + return FAILURE; + } + if (item.get_identifier().empty()) { + Logger::error("Cannot add item to the ", name, " registry - empty identifier!"); + return FAILURE; + } + T const* old_item = get_item_by_identifier(item.get_identifier()); + if (old_item != nullptr) { + Logger::error("Cannot add item to the ", name, " registry - an item with the identifier \"", item.get_identifier(), "\" already exists!"); + return FAILURE; + } + items.push_back(item); + return SUCCESS; + } + void lock() { + if (locked) { + Logger::error("Failed to lock ", name, " registry - already locked!"); + } else { + locked = true; + Logger::info("Locked ", name, " registry after registering ", get_item_count(), " items"); + } + } + bool is_locked() const { + return locked; + } + size_t get_item_count() const { + return items.size(); + } + T* get_item_by_identifier(std::string const& identifier) { + if (!identifier.empty()) + for (T& item : items) + if (item.get_identifier() == identifier) return &item; + return nullptr; + } + T const* get_item_by_identifier(std::string const& identifier) const { + if (!identifier.empty()) + for (T const& item : items) + if (item.get_identifier() == identifier) return &item; + return nullptr; + } + T* get_item_by_index(size_t index) { + return index < items.size() ? &items[index] : nullptr; + } + T const* get_item_by_index(size_t index) const { + return index < items.size() ? &items[index] : nullptr; + } + std::vector& get_items() { + return items; + } + std::vector const& get_items() const { + return items; + } + }; } diff --git a/extension/src/openvic2/map/Building.cpp b/extension/src/openvic2/map/Building.cpp index f453a0f..3643b4e 100644 --- a/extension/src/openvic2/map/Building.cpp +++ b/extension/src/openvic2/map/Building.cpp @@ -6,7 +6,7 @@ using namespace OpenVic2; -Building::Building(BuildingType const& new_type) : type{ new_type } {} +Building::Building(BuildingType const& new_type) : HasIdentifier{ new_type.get_identifier() }, type{ new_type } {} bool Building::_can_expand() const { return level < type.get_max_level(); @@ -45,6 +45,9 @@ return_t Building::expand() { return FAILURE; } +/* REQUIREMENTS: + * MAP-71, MAP-74, MAP-77 + */ void Building::update_state(Date const& today) { switch (expansion_state) { case ExpansionState::Preparing: @@ -84,15 +87,9 @@ Timespan BuildingType::get_build_time() const { return build_time; } +const char BuildingManager::building_types_name[] = "building types"; + return_t BuildingManager::add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time) { - if (building_types_locked) { - Logger::error("The building type list has already been locked!"); - return FAILURE; - } - if (identifier.empty()) { - Logger::error("Empty building type identifier!"); - return FAILURE; - } if (max_level < 0) { Logger::error("Invalid building type max level: ", max_level); return FAILURE; @@ -101,29 +98,18 @@ return_t BuildingManager::add_building_type(std::string const& identifier, Build Logger::error("Invalid building type build time: ", build_time); return FAILURE; } - BuildingType new_building_type{ identifier, max_level, build_time }; - BuildingType const* old_building_type = get_building_type_by_identifier(identifier); - if (old_building_type != nullptr) { - Logger::error("Duplicate building type identifiers: ", old_building_type->get_identifier(), " and ", identifier); - return FAILURE; - } - building_types.push_back(new_building_type); - return SUCCESS; + return building_types.add_item({ identifier, max_level, build_time }); } void BuildingManager::lock_building_types() { - building_types_locked = true; - Logger::info("Locked building types after registering ", building_types.size()); + building_types.lock(); } BuildingType const* BuildingManager::get_building_type_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (BuildingType const& building_type : building_types) - if (building_type.get_identifier() == identifier) return &building_type; - return nullptr; + return building_types.get_item_by_identifier(identifier); } void BuildingManager::generate_province_buildings(std::vector& buildings) const { - for (BuildingType const& type : building_types) + for (BuildingType const& type : building_types.get_items()) buildings.push_back(Building{ type }); } diff --git a/extension/src/openvic2/map/Building.hpp b/extension/src/openvic2/map/Building.hpp index 7a1a777..08ede3a 100644 --- a/extension/src/openvic2/map/Building.hpp +++ b/extension/src/openvic2/map/Building.hpp @@ -9,7 +9,12 @@ namespace OpenVic2 { struct BuildingManager; struct BuildingType; - struct Building { + /* REQUIREMENTS: + * MAP-11, MAP-72, MAP-73 + * MAP-12, MAP-75, MAP-76 + * MAP-13, MAP-78, MAP-79 + */ + struct Building : HasIdentifier { friend struct BuildingManager; using level_t = int8_t; @@ -52,8 +57,8 @@ namespace OpenVic2 { struct BuildingManager { private: - std::vector building_types; - bool building_types_locked = false; + static const char building_types_name[]; + IdentifierRegistry building_types; public: return_t add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time); void lock_building_types(); diff --git a/extension/src/openvic2/map/Map.cpp b/extension/src/openvic2/map/Map.cpp index 1089d61..a440f67 100644 --- a/extension/src/openvic2/map/Map.cpp +++ b/extension/src/openvic2/map/Map.cpp @@ -16,45 +16,32 @@ Mapmode::index_t Mapmode::get_index() const { return index; } -Mapmode::colour_func_t Mapmode::get_colour_func() const { - return colour_func; +Province::colour_t Mapmode::get_colour(Map const& map, Province const& province) const { + return colour_func ? colour_func(map, province) : Province::NULL_COLOUR; } +const char Map::provinces_name[] = "provinces", Map::regions_name[] = "regions", Map::mapmodes_name[] = "mapmodes"; + return_t Map::add_province(std::string const& identifier, Province::colour_t colour) { - if (provinces_locked) { - Logger::error("The map's province list has already been locked!"); - return FAILURE; - } - if (provinces.size() >= Province::MAX_INDEX) { + if (provinces.get_item_count() >= Province::MAX_INDEX) { Logger::error("The map's province list is full - there can be at most ", Province::MAX_INDEX, " provinces"); return FAILURE; } - if (identifier.empty()) { - Logger::error("Empty province identifier for colour ", Province::colour_to_hex_string(colour)); - return FAILURE; - } if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { Logger::error("Invalid province colour: ", Province::colour_to_hex_string(colour)); return FAILURE; } - Province new_province{ static_cast(provinces.size() + 1), identifier, colour }; - Province const* old_province = get_province_by_identifier(identifier); - if (old_province != nullptr) { - Logger::error("Duplicate province identifiers: ", old_province->to_string(), " and ", new_province.to_string()); - return FAILURE; - } - old_province = get_province_by_colour(colour); + Province new_province{ static_cast(provinces.get_item_count() + 1), identifier, colour }; + Province const* old_province = get_province_by_colour(colour); if (old_province != nullptr) { Logger::error("Duplicate province colours: ", old_province->to_string(), " and ", new_province.to_string()); return FAILURE; } - provinces.push_back(new_province); - return SUCCESS; + return provinces.add_item(std::move(new_province)); } void Map::lock_provinces() { - provinces_locked = true; - Logger::info("Locked provinces after registering ", provinces.size()); + provinces.lock(); } return_t Map::set_water_province(std::string const& identifier) { @@ -82,18 +69,6 @@ void Map::lock_water_provinces() { } return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers) { - if (regions_locked) { - Logger::error("The map's region list has already been locked!"); - return FAILURE; - } - if (identifier.empty()) { - Logger::error("Empty region identifier!"); - return FAILURE; - } - if (provinces.empty()) { - Logger::error("Empty province list for region ", identifier); - return FAILURE; - } return_t ret = SUCCESS; Region new_region{ identifier }; for (std::string const& province_identifier : province_identifiers) { @@ -106,8 +81,8 @@ return_t Map::add_region(std::string const& identifier, std::vector size_t other_region_index = reinterpret_cast(province->get_region()); if (other_region_index != 0) { other_region_index--; - if (other_region_index < regions.size()) - Logger::error("Province ", province_identifier, " is already part of ", regions[other_region_index].get_identifier()); + if (other_region_index < regions.get_item_count()) + Logger::error("Province ", province_identifier, " is already part of ", regions.get_item_by_index(other_region_index)->get_identifier()); else Logger::error("Province ", province_identifier, " is already part of an unknown region with index ", other_region_index); ret = FAILURE; @@ -122,65 +97,53 @@ return_t Map::add_region(std::string const& identifier, std::vector Logger::error("No valid provinces in region's list"); return FAILURE; } - Region const* old_region = get_region_by_identifier(identifier); - if (old_region != nullptr) { - Logger::error("Duplicate region identifiers: ", old_region->get_identifier(), " and ", identifier); - return FAILURE; - } - regions.push_back(new_region); // Used to detect provinces listed in multiple regions, will // be corrected once regions is stable (i.e. lock_regions). - Region* tmp_region_index = reinterpret_cast(regions.size()); + Region* tmp_region_index = reinterpret_cast(regions.get_item_count()); for (Province* province : new_region.get_provinces()) province->region = tmp_region_index; + if (regions.add_item(std::move(new_region)) != SUCCESS) ret = FAILURE; return ret; } void Map::lock_regions() { - regions_locked = true; - for (Region& region : regions) + regions.lock(); + for (Region& region : regions.get_items()) for (Province* province : region.get_provinces()) province->region = ®ion; - Logger::info("Locked regions after registering ", regions.size()); } size_t Map::get_province_count() const { - return provinces.size(); + return provinces.get_item_count(); } Province* Map::get_province_by_index(Province::index_t index) { - return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; + return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; } Province const* Map::get_province_by_index(Province::index_t index) const { - return index != Province::NULL_INDEX && index <= provinces.size() ? &provinces[index - 1] : nullptr; + return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; } Province* Map::get_province_by_identifier(std::string const& identifier) { - if (!identifier.empty()) - for (Province& province : provinces) - if (province.get_identifier() == identifier) return &province; - return nullptr; + return provinces.get_item_by_identifier(identifier); } Province const* Map::get_province_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Province const& province : provinces) - if (province.get_identifier() == identifier) return &province; - return nullptr; + return provinces.get_item_by_identifier(identifier); } Province* Map::get_province_by_colour(Province::colour_t colour) { if (colour != Province::NULL_COLOUR) - for (Province& province : provinces) + for (Province& province : provinces.get_items()) if (province.get_colour() == colour) return &province; return nullptr; } Province const* Map::get_province_by_colour(Province::colour_t colour) const { if (colour != Province::NULL_COLOUR) - for (Province const& province : provinces) + for (Province const& province : provinces.get_items()) if (province.get_colour() == colour) return &province; return nullptr; } @@ -191,17 +154,11 @@ Province::index_t Map::get_province_index_at(size_t x, size_t y) const { } Region* Map::get_region_by_identifier(std::string const& identifier) { - if (!identifier.empty()) - for (Region& region : regions) - if (region.get_identifier() == identifier) return ®ion; - return nullptr; + return regions.get_item_by_identifier(identifier); } Region const* Map::get_region_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Region const& region : regions) - if (region.get_identifier() == identifier) return ®ion; - return nullptr; + return regions.get_item_by_identifier(identifier); } static Province::colour_t colour_at(uint8_t const* colour_data, int32_t idx) { @@ -213,7 +170,7 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, Logger::error("Province index image has already been generated!"); return FAILURE; } - if (!provinces_locked) { + if (!provinces.is_locked()) { Logger::error("Province index image cannot be generated until after provinces are locked!"); return FAILURE; } @@ -229,7 +186,7 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, height = new_height; province_index_image.resize(width * height); - std::vector province_checklist(provinces.size()); + std::vector province_checklist(provinces.get_item_count()); return_t ret = SUCCESS; std::unordered_set unrecognised_colours; @@ -269,7 +226,7 @@ return_t Map::generate_province_index_image(size_t new_width, size_t new_height, for (size_t idx = 0; idx < province_checklist.size(); ++idx) { if (!province_checklist[idx]) { - Logger::error("Province missing from shape image: ", provinces[idx].to_string()); + Logger::error("Province missing from shape image: ", provinces.get_item_by_index(idx)->to_string()); ret = FAILURE; } } @@ -289,37 +246,27 @@ std::vector const& Map::get_province_index_image() const { } return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func) { - if (identifier.empty()) { - Logger::error("Empty mapmode identifier!"); - return FAILURE; - } if (colour_func == nullptr) { Logger::error("Mapmode colour function is null for identifier: ", identifier); return FAILURE; } - Mapmode new_mapmode{ mapmodes.size(), identifier, colour_func }; - Mapmode const* old_mapmode = get_mapmode_by_identifier(identifier); - if (old_mapmode != nullptr) { - Logger::error("Duplicate mapmode identifiers: ", old_mapmode->get_identifier(), " and ", identifier); - return FAILURE; - } - mapmodes.push_back(new_mapmode); - return SUCCESS; + return mapmodes.add_item({ mapmodes.get_item_count(), identifier, colour_func }); +} + +void Map::lock_mapmodes() { + mapmodes.lock(); } size_t Map::get_mapmode_count() const { - return mapmodes.size(); + return mapmodes.get_item_count(); } Mapmode const* Map::get_mapmode_by_index(size_t index) const { - return index < mapmodes.size() ? &mapmodes[index] : nullptr; + return mapmodes.get_item_by_index(index); } Mapmode const* Map::get_mapmode_by_identifier(std::string const& identifier) const { - if (!identifier.empty()) - for (Mapmode const& mapmode : mapmodes) - if (mapmode.get_identifier() == identifier) return &mapmode; - return nullptr; + return mapmodes.get_item_by_identifier(identifier); } return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const { @@ -327,14 +274,14 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) Logger::error("Mapmode colour target pointer is null!"); return FAILURE; } - if (index >= mapmodes.size()) { + Mapmode const* mapmode = mapmodes.get_item_by_index(index); + if (mapmode == nullptr) { Logger::error("Invalid mapmode index: ", index); return FAILURE; } - Mapmode const& mapmode = mapmodes[index]; target += 4; // Skip past Province::NULL_INDEX - for (Province const& province : provinces) { - const Province::colour_t colour = mapmode.get_colour_func()(*this, province); + for (Province const& province : provinces.get_items()) { + const Province::colour_t colour = mapmode->get_colour(*this, province); *target++ = (colour >> 16) & 0xFF; *target++ = (colour >> 8) & 0xFF; *target++ = colour & 0xFF; @@ -344,16 +291,16 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) } void Map::generate_province_buildings(BuildingManager const& manager) { - for (Province& province : provinces) - manager.generate_province_buildings(province.buildings); + for (Province& province : provinces.get_items()) + manager.generate_province_buildings(province.buildings.get_items()); } void Map::update_state(Date const& today) { - for (Province& province : provinces) + for (Province& province : provinces.get_items()) province.update_state(today); } void Map::tick(Date const& today) { - for (Province& province : provinces) + for (Province& province : provinces.get_items()) province.tick(today); } diff --git a/extension/src/openvic2/map/Map.hpp b/extension/src/openvic2/map/Map.hpp index b6e7ac2..ed63912 100644 --- a/extension/src/openvic2/map/Map.hpp +++ b/extension/src/openvic2/map/Map.hpp @@ -18,7 +18,7 @@ namespace OpenVic2 { Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); public: index_t get_index() const; - colour_func_t get_colour_func() const; + Province::colour_t get_colour(Map const& map, Province const& province) const; }; /* REQUIREMENTS: @@ -26,14 +26,15 @@ namespace OpenVic2 { */ struct Map { private: - std::vector provinces; - std::vector regions; - bool provinces_locked = false, water_provinces_locked = false, regions_locked = false; + static const char provinces_name[], regions_name[], mapmodes_name[]; + IdentifierRegistry provinces; + IdentifierRegistry regions; + IdentifierRegistry mapmodes; + bool water_provinces_locked = false; size_t water_province_count = 0; size_t width = 0, height = 0; std::vector province_index_image; - std::vector mapmodes; public: return_t add_province(std::string const& identifier, Province::colour_t colour); void lock_provinces(); @@ -60,6 +61,7 @@ namespace OpenVic2 { std::vector const& get_province_index_image() const; return_t add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func); + void lock_mapmodes(); size_t get_mapmode_count() const; Mapmode const* get_mapmode_by_index(Mapmode::index_t index) const; Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; diff --git a/extension/src/openvic2/map/Province.cpp b/extension/src/openvic2/map/Province.cpp index c641b7e..08711af 100644 --- a/extension/src/openvic2/map/Province.cpp +++ b/extension/src/openvic2/map/Province.cpp @@ -6,6 +6,8 @@ using namespace OpenVic2; +const char Province::buildings_name[] = "buildings"; + Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : HasIdentifier{ new_identifier }, index{ new_index }, colour{ new_colour } { assert(index != NULL_INDEX); @@ -39,14 +41,13 @@ Province::life_rating_t Province::get_life_rating() const { } std::vector const& Province::get_buildings() const { - return buildings; + return buildings.get_items(); } return_t Province::expand_building(std::string const& building_type_identifier) { - for (Building& building : buildings) - if (building.get_type().get_identifier() == building_type_identifier) - return building.expand(); - return FAILURE; + Building* building = buildings.get_item_by_identifier(building_type_identifier); + if (building == nullptr) return FAILURE; + return building->expand(); } std::string Province::to_string() const { @@ -56,12 +57,12 @@ std::string Province::to_string() const { } void Province::update_state(Date const& today) { - for (Building& building : buildings) + for (Building& building : buildings.get_items()) building.update_state(today); } void Province::tick(Date const& today) { - for (Building& building : buildings) + for (Building& building : buildings.get_items()) building.tick(today); } diff --git a/extension/src/openvic2/map/Province.hpp b/extension/src/openvic2/map/Province.hpp index 79c6861..0b7cd4c 100644 --- a/extension/src/openvic2/map/Province.hpp +++ b/extension/src/openvic2/map/Province.hpp @@ -24,7 +24,8 @@ namespace OpenVic2 { Region* region = nullptr; bool water = false; life_rating_t life_rating = 0; - std::vector buildings; + static const char buildings_name[]; + IdentifierRegistry buildings; Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); public: diff --git a/game/localisation/en_GB/menus.csv b/game/localisation/en_GB/menus.csv index 0009acd..3c3fff1 100644 --- a/game/localisation/en_GB/menus.csv +++ b/game/localisation/en_GB/menus.csv @@ -69,6 +69,7 @@ DIALOG_SAVE_AND_QUIT,Save and Quit ,, Province Overview Panel province_MISSING,No Province region_MISSING,No Region +LIFE_RATING_TOOLTIP,Liferating: %d building_MISSING,No Building building_fort,Fort building_naval_base,Naval Base diff --git a/game/src/GameSession/GameSpeedPanel.gd b/game/src/GameSession/GameSpeedPanel.gd index 8b7af29..80708b1 100644 --- a/game/src/GameSession/GameSpeedPanel.gd +++ b/game/src/GameSession/GameSpeedPanel.gd @@ -7,7 +7,6 @@ extends PanelContainer @export var _decrease_speed_button : Button @export var _increase_speed_button : Button -# Called when the node enters the scene tree for the first time. func _ready(): GameSingleton.state_updated.connect(_update_buttons) _update_buttons() diff --git a/game/src/GameSession/ProvinceOverviewPanel.gd b/game/src/GameSession/ProvinceOverviewPanel.gd index cbab9d0..17da9d0 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.gd +++ b/game/src/GameSession/ProvinceOverviewPanel.gd @@ -2,6 +2,7 @@ extends PanelContainer @export var _province_name_label : Label @export var _region_name_label : Label +@export var _life_rating_bar : ProgressBar @export var _buildings_container : Container const _missing_suffix : String = "_MISSING" @@ -23,6 +24,10 @@ func _expand_building(building_identifier : String) -> void: if GameSingleton.expand_building(_selected_index, building_identifier) != OK: push_error("Failed to expand ", building_identifier, " in province #", _selected_index); +# REQUIREMENTS: +# * UI-183, UI-185, UI-186, UI-765, UI-187, UI-188, UI-189 +# * UI-191, UI-193, UI-194, UI-766, UI-195, UI-196, UI-197 +# * UI-199, UI-201, UI-202, UI-767, UI-203, UI-204, UI-205 func _add_building(building : Dictionary) -> void: const _building_key : StringName = &"building" const _level_key : StringName = &"level" @@ -62,11 +67,16 @@ func update_info() -> void: const _life_rating_key : StringName = &"life_rating" const _buildings_key : StringName = &"buildings" + const _life_rating_tooltip : String = "LIFE_RATING_TOOLTIP" + _province_info = GameSingleton.get_province_info_from_index(_selected_index) if _province_info: _province_name_label.text = _province_info.get(_province_key, _province_key + _missing_suffix) _region_name_label.text = _province_info.get(_region_key, _region_key + _missing_suffix) + _life_rating_bar.value = _province_info.get(_life_rating_key, 0) + _life_rating_bar.tooltip_text = tr(_life_rating_tooltip) % _life_rating_bar.value + for child in _buildings_container.get_children(): _buildings_container.remove_child(child) child.queue_free() diff --git a/game/src/GameSession/ProvinceOverviewPanel.tscn b/game/src/GameSession/ProvinceOverviewPanel.tscn index 7b28cc1..48e7c25 100644 --- a/game/src/GameSession/ProvinceOverviewPanel.tscn +++ b/game/src/GameSession/ProvinceOverviewPanel.tscn @@ -2,7 +2,7 @@ [ext_resource type="Script" path="res://src/GameSession/ProvinceOverviewPanel.gd" id="1_3n8k5"] -[node name="ProvinceOverviewPanel" type="PanelContainer" node_paths=PackedStringArray("_province_name_label", "_region_name_label", "_buildings_container")] +[node name="ProvinceOverviewPanel" type="PanelContainer" node_paths=PackedStringArray("_province_name_label", "_region_name_label", "_life_rating_bar", "_buildings_container")] editor_description = "UI-56" anchors_preset = 2 anchor_top = 1.0 @@ -13,6 +13,7 @@ grow_vertical = 0 script = ExtResource("1_3n8k5") _province_name_label = NodePath("PanelList/TopBarList/NameList/ProvinceName") _region_name_label = NodePath("PanelList/TopBarList/NameList/RegionName") +_life_rating_bar = NodePath("PanelList/TopBarList/NameList/LifeRatingBar") _buildings_container = NodePath("PanelList/InteractList/BuildingsContainer") [node name="PanelList" type="VBoxContainer" parent="."] @@ -38,6 +39,10 @@ layout_mode = 2 text = "region_MISSING" vertical_alignment = 1 +[node name="LifeRatingBar" type="ProgressBar" parent="PanelList/TopBarList/NameList"] +editor_description = "UI-62" +layout_mode = 2 + [node name="CloseButton" type="Button" parent="PanelList/TopBarList"] custom_minimum_size = Vector2(30, 30) layout_mode = 2 -- cgit v1.2.3-56-ga3b1 From 50327abf33078c44fef85c62ce3d90e23056fb34 Mon Sep 17 00:00:00 2001 From: Hop311 Date: Tue, 25 Apr 2023 21:35:59 +0100 Subject: Further cleanup + reset on return to main menu --- extension/src/GameSingleton.cpp | 6 ++--- extension/src/GameSingleton.hpp | 2 +- extension/src/openvic2/GameAdvancementHook.cpp | 5 ++++ extension/src/openvic2/GameAdvancementHook.hpp | 5 ++-- extension/src/openvic2/GameManager.cpp | 9 ++++--- extension/src/openvic2/GameManager.hpp | 4 ++-- extension/src/openvic2/Types.hpp | 33 +++++++++++++++++++------- extension/src/openvic2/map/Building.cpp | 15 +++++++++--- extension/src/openvic2/map/Building.hpp | 21 ++++++++++------ extension/src/openvic2/map/Map.cpp | 22 +++++++++++++---- extension/src/openvic2/map/Map.hpp | 15 ++++++------ extension/src/openvic2/map/Province.cpp | 16 ++++++++++--- extension/src/openvic2/map/Province.hpp | 12 ++++++---- extension/src/openvic2/map/Region.hpp | 2 ++ game/src/Autoload/Events.gd | 1 - game/src/GameSession/GameSession.gd | 2 ++ game/src/GameSession/GameSessionMenu.gd | 1 - 17 files changed, 121 insertions(+), 50 deletions(-) diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp index f596cc2..32d940c 100644 --- a/extension/src/GameSingleton.cpp +++ b/extension/src/GameSingleton.cpp @@ -18,7 +18,7 @@ void GameSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("load_water_province_file", "file_path"), &GameSingleton::load_water_province_file); ClassDB::bind_method(D_METHOD("load_region_file", "file_path"), &GameSingleton::load_region_file); ClassDB::bind_method(D_METHOD("load_province_shape_file", "file_path"), &GameSingleton::load_province_shape_file); - ClassDB::bind_method(D_METHOD("finished_loading_data"), &GameSingleton::finished_loading_data); + ClassDB::bind_method(D_METHOD("setup"), &GameSingleton::setup); ClassDB::bind_method(D_METHOD("get_province_index_from_uv_coords", "coords"), &GameSingleton::get_province_index_from_uv_coords); ClassDB::bind_method(D_METHOD("get_province_info_from_index", "index"), &GameSingleton::get_province_info_from_index); @@ -273,8 +273,8 @@ Error GameSingleton::load_province_shape_file(String const& file_path) { return err; } -void GameSingleton::finished_loading_data() { - game_manager.finished_loading_data(); +godot::Error GameSingleton::setup() { + return ERR(game_manager.setup()); } Error GameSingleton::load_water_province_file(String const& file_path) { diff --git a/extension/src/GameSingleton.hpp b/extension/src/GameSingleton.hpp index 0e2cfd1..815c92f 100644 --- a/extension/src/GameSingleton.hpp +++ b/extension/src/GameSingleton.hpp @@ -33,7 +33,7 @@ namespace OpenVic2 { godot::Error load_water_province_file(godot::String const& file_path); godot::Error load_region_file(godot::String const& file_path); godot::Error load_province_shape_file(godot::String const& file_path); - void finished_loading_data(); + godot::Error setup(); int32_t get_province_index_from_uv_coords(godot::Vector2 const& coords) const; godot::Dictionary get_province_info_from_index(int32_t index) const; diff --git a/extension/src/openvic2/GameAdvancementHook.cpp b/extension/src/openvic2/GameAdvancementHook.cpp index c78847b..4b9bc25 100644 --- a/extension/src/openvic2/GameAdvancementHook.cpp +++ b/extension/src/openvic2/GameAdvancementHook.cpp @@ -65,3 +65,8 @@ void GameAdvancementHook::conditionallyAdvanceGame() { } if (refreshFunction) refreshFunction(); } + +void GameAdvancementHook::reset() { + isPaused = true; + currentSpeed = 0; +} diff --git a/extension/src/openvic2/GameAdvancementHook.hpp b/extension/src/openvic2/GameAdvancementHook.hpp index 572494a..07f8414 100644 --- a/extension/src/openvic2/GameAdvancementHook.hpp +++ b/extension/src/openvic2/GameAdvancementHook.hpp @@ -21,12 +21,12 @@ namespace OpenVic2 { //A function pointer that advances the simulation, intended to be a capturing lambda or something similar. May need to be reworked later AdvancementFunction triggerFunction; RefreshFunction refreshFunction; + speed_t currentSpeed; public: bool isPaused; - speed_t currentSpeed; - GameAdvancementHook(AdvancementFunction tickFunction, RefreshFunction updateFunction, bool startPaused = false, speed_t startingSpeed = 0); + GameAdvancementHook(AdvancementFunction tickFunction, RefreshFunction updateFunction, bool startPaused = true, speed_t startingSpeed = 0); void setSimulationSpeed(speed_t speed); speed_t getSimulationSpeed() const; @@ -37,5 +37,6 @@ namespace OpenVic2 { GameAdvancementHook& operator++(); GameAdvancementHook& operator--(); void conditionallyAdvanceGame(); + void reset(); }; } \ No newline at end of file diff --git a/extension/src/openvic2/GameManager.cpp b/extension/src/openvic2/GameManager.cpp index da742ca..78992f1 100644 --- a/extension/src/openvic2/GameManager.cpp +++ b/extension/src/openvic2/GameManager.cpp @@ -5,7 +5,7 @@ using namespace OpenVic2; GameManager::GameManager(state_updated_func_t state_updated_callback) - : clock{ [this]() { tick(); }, [this]() { update_state(); }, true }, today{ 1836 }, state_updated{ state_updated_callback } {} + : clock{ [this]() { tick(); }, [this]() { update_state(); } }, state_updated{ state_updated_callback } {} void GameManager::set_needs_update() { needs_update = true; @@ -27,8 +27,11 @@ void GameManager::tick() { set_needs_update(); } -void GameManager::finished_loading_data() { - map.generate_province_buildings(building_manager); +return_t GameManager::setup() { + clock.reset(); + today = { 1836 }; + set_needs_update(); + return map.generate_province_buildings(building_manager); } Date const& GameManager::get_today() const { diff --git a/extension/src/openvic2/GameManager.hpp b/extension/src/openvic2/GameManager.hpp index cba0180..65cd566 100644 --- a/extension/src/openvic2/GameManager.hpp +++ b/extension/src/openvic2/GameManager.hpp @@ -13,7 +13,7 @@ namespace OpenVic2 { private: Date today; state_updated_func_t state_updated; - bool needs_update = true; + bool needs_update; void set_needs_update(); void update_state(); @@ -21,7 +21,7 @@ namespace OpenVic2 { public: GameManager(state_updated_func_t state_updated_callback); - void finished_loading_data(); + return_t setup(); Date const& get_today() const; return_t expand_building(Province::index_t province_index, std::string const& building_type_identifier); diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp index 226dd30..f53f842 100644 --- a/extension/src/openvic2/Types.hpp +++ b/extension/src/openvic2/Types.hpp @@ -10,47 +10,62 @@ namespace OpenVic2 { // This mirrors godot::Error, where `OK = 0` and `FAILED = 1`. static constexpr return_t SUCCESS = false, FAILURE = true; + /* + * Base class for objects with a non-empty string identifier, + * uniquely named instances of which can be entered into an + * IdentifierRegistry instance. + */ class HasIdentifier { - std::string identifier; + const std::string identifier; protected: HasIdentifier(std::string const& new_identifier); public: + HasIdentifier(HasIdentifier const&) = delete; + HasIdentifier(HasIdentifier&&) = default; std::string const& get_identifier() const; }; - template::value>::type* = nullptr> + /* + * Template for a list of objects with unique string identifiers that can + * be locked to prevent any further additions. The template argument T is + * the type of object that the registry will store, and the second part ensures + * that HasIdentifier is a base class of T. + */ + template::value>::type* = nullptr> class IdentifierRegistry { + const std::string name; std::vector items; bool locked = false; public: + IdentifierRegistry(std::string const& new_name) : name(new_name) {} return_t add_item(T&& item) { if (locked) { Logger::error("Cannot add item to the ", name, " registry - locked!"); return FAILURE; } - if (item.get_identifier().empty()) { - Logger::error("Cannot add item to the ", name, " registry - empty identifier!"); - return FAILURE; - } T const* old_item = get_item_by_identifier(item.get_identifier()); if (old_item != nullptr) { Logger::error("Cannot add item to the ", name, " registry - an item with the identifier \"", item.get_identifier(), "\" already exists!"); return FAILURE; } - items.push_back(item); + items.push_back(std::move(item)); return SUCCESS; } - void lock() { + void lock(bool log = true) { if (locked) { Logger::error("Failed to lock ", name, " registry - already locked!"); } else { locked = true; - Logger::info("Locked ", name, " registry after registering ", get_item_count(), " items"); + if (log) Logger::info("Locked ", name, " registry after registering ", get_item_count(), " items"); } } bool is_locked() const { return locked; } + void reset() { + items.clear(); + locked = false; + } size_t get_item_count() const { return items.size(); } diff --git a/extension/src/openvic2/map/Building.cpp b/extension/src/openvic2/map/Building.cpp index 3643b4e..00e121b 100644 --- a/extension/src/openvic2/map/Building.cpp +++ b/extension/src/openvic2/map/Building.cpp @@ -3,6 +3,7 @@ #include #include "openvic2/Logger.hpp" +#include "openvic2/map/Province.hpp" using namespace OpenVic2; @@ -87,9 +88,13 @@ Timespan BuildingType::get_build_time() const { return build_time; } -const char BuildingManager::building_types_name[] = "building types"; +BuildingManager::BuildingManager() : building_types{ "building types" } {} return_t BuildingManager::add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time) { + if (identifier.empty()) { + Logger::error("Invalid building type identifier - empty!"); + return FAILURE; + } if (max_level < 0) { Logger::error("Invalid building type max level: ", max_level); return FAILURE; @@ -109,7 +114,11 @@ BuildingType const* BuildingManager::get_building_type_by_identifier(std::string return building_types.get_item_by_identifier(identifier); } -void BuildingManager::generate_province_buildings(std::vector& buildings) const { +return_t BuildingManager::generate_province_buildings(Province& province) const { + return_t ret = SUCCESS; + province.reset_buildings(); for (BuildingType const& type : building_types.get_items()) - buildings.push_back(Building{ type }); + if (province.add_building(type) != SUCCESS) ret = FAILURE; + province.lock_buildings(); + return ret; } diff --git a/extension/src/openvic2/map/Building.hpp b/extension/src/openvic2/map/Building.hpp index 08ede3a..1305014 100644 --- a/extension/src/openvic2/map/Building.hpp +++ b/extension/src/openvic2/map/Building.hpp @@ -6,7 +6,7 @@ #include "openvic2/Date.hpp" namespace OpenVic2 { - struct BuildingManager; + struct Province; struct BuildingType; /* REQUIREMENTS: @@ -15,7 +15,7 @@ namespace OpenVic2 { * MAP-13, MAP-78, MAP-79 */ struct Building : HasIdentifier { - friend struct BuildingManager; + friend struct Province; using level_t = int8_t; @@ -31,6 +31,8 @@ namespace OpenVic2 { bool _can_expand() const; public: + Building(Building&&) = default; + BuildingType const& get_type() const; level_t get_level() const; ExpansionState get_expansion_state() const; @@ -43,26 +45,31 @@ namespace OpenVic2 { void tick(Date const& today); }; + struct BuildingManager; + struct BuildingType : HasIdentifier { friend struct BuildingManager; private: - Building::level_t max_level; - Timespan build_time; + const Building::level_t max_level; + const Timespan build_time; BuildingType(std::string const& new_identifier, Building::level_t new_max_level, Timespan new_build_time); public: + BuildingType(BuildingType&&) = default; + Building::level_t get_max_level() const; Timespan get_build_time() const; }; struct BuildingManager { private: - static const char building_types_name[]; - IdentifierRegistry building_types; + IdentifierRegistry building_types; public: + BuildingManager(); + return_t add_building_type(std::string const& identifier, Building::level_t max_level, Timespan build_time); void lock_building_types(); BuildingType const* get_building_type_by_identifier(std::string const& identifier) const; - void generate_province_buildings(std::vector& buildings) const; + return_t generate_province_buildings(Province& province) const; }; } diff --git a/extension/src/openvic2/map/Map.cpp b/extension/src/openvic2/map/Map.cpp index a440f67..b5cf144 100644 --- a/extension/src/openvic2/map/Map.cpp +++ b/extension/src/openvic2/map/Map.cpp @@ -20,13 +20,17 @@ Province::colour_t Mapmode::get_colour(Map const& map, Province const& province) return colour_func ? colour_func(map, province) : Province::NULL_COLOUR; } -const char Map::provinces_name[] = "provinces", Map::regions_name[] = "regions", Map::mapmodes_name[] = "mapmodes"; +Map::Map() : provinces{ "provinces" }, regions{ "regions" }, mapmodes{ "mapmodes" } {} return_t Map::add_province(std::string const& identifier, Province::colour_t colour) { if (provinces.get_item_count() >= Province::MAX_INDEX) { Logger::error("The map's province list is full - there can be at most ", Province::MAX_INDEX, " provinces"); return FAILURE; } + if (identifier.empty()) { + Logger::error("Invalid province identifier - empty!"); + return FAILURE; + } if (colour == Province::NULL_COLOUR || colour > Province::MAX_COLOUR) { Logger::error("Invalid province colour: ", Province::colour_to_hex_string(colour)); return FAILURE; @@ -69,8 +73,12 @@ void Map::lock_water_provinces() { } return_t Map::add_region(std::string const& identifier, std::vector const& province_identifiers) { - return_t ret = SUCCESS; + if (identifier.empty()) { + Logger::error("Invalid region identifier - empty!"); + return FAILURE; + } Region new_region{ identifier }; + return_t ret = SUCCESS; for (std::string const& province_identifier : province_identifiers) { Province* province = get_province_by_identifier(province_identifier); if (province != nullptr) { @@ -246,6 +254,10 @@ std::vector const& Map::get_province_index_image() const { } return_t Map::add_mapmode(std::string const& identifier, Mapmode::colour_func_t colour_func) { + if (identifier.empty()) { + Logger::error("Invalid mapmode identifier - empty!"); + return FAILURE; + } if (colour_func == nullptr) { Logger::error("Mapmode colour function is null for identifier: ", identifier); return FAILURE; @@ -290,9 +302,11 @@ return_t Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) return SUCCESS; } -void Map::generate_province_buildings(BuildingManager const& manager) { +return_t Map::generate_province_buildings(BuildingManager const& manager) { + return_t ret = SUCCESS; for (Province& province : provinces.get_items()) - manager.generate_province_buildings(province.buildings.get_items()); + if (manager.generate_province_buildings(province) != SUCCESS) ret = FAILURE; + return ret; } void Map::update_state(Date const& today) { diff --git a/extension/src/openvic2/map/Map.hpp b/extension/src/openvic2/map/Map.hpp index ed63912..ebc23be 100644 --- a/extension/src/openvic2/map/Map.hpp +++ b/extension/src/openvic2/map/Map.hpp @@ -12,8 +12,8 @@ namespace OpenVic2 { using colour_func_t = std::function; using index_t = size_t; private: - index_t index; - colour_func_t colour_func; + const index_t index; + const colour_func_t colour_func; Mapmode(index_t new_index, std::string const& new_identifier, colour_func_t new_colour_func); public: @@ -26,16 +26,17 @@ namespace OpenVic2 { */ struct Map { private: - static const char provinces_name[], regions_name[], mapmodes_name[]; - IdentifierRegistry provinces; - IdentifierRegistry regions; - IdentifierRegistry mapmodes; + IdentifierRegistry provinces; + IdentifierRegistry regions; + IdentifierRegistry mapmodes; bool water_provinces_locked = false; size_t water_province_count = 0; size_t width = 0, height = 0; std::vector province_index_image; public: + Map(); + return_t add_province(std::string const& identifier, Province::colour_t colour); void lock_provinces(); return_t set_water_province(std::string const& identifier); @@ -67,7 +68,7 @@ namespace OpenVic2 { Mapmode const* get_mapmode_by_identifier(std::string const& identifier) const; return_t generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; - void generate_province_buildings(BuildingManager const& manager); + return_t generate_province_buildings(BuildingManager const& manager); void update_state(Date const& today); void tick(Date const& today); diff --git a/extension/src/openvic2/map/Province.cpp b/extension/src/openvic2/map/Province.cpp index 08711af..4360bce 100644 --- a/extension/src/openvic2/map/Province.cpp +++ b/extension/src/openvic2/map/Province.cpp @@ -6,10 +6,8 @@ using namespace OpenVic2; -const char Province::buildings_name[] = "buildings"; - Province::Province(index_t new_index, std::string const& new_identifier, colour_t new_colour) : - HasIdentifier{ new_identifier }, index{ new_index }, colour{ new_colour } { + HasIdentifier{ new_identifier }, index{ new_index }, colour{ new_colour }, buildings{ "buildings" } { assert(index != NULL_INDEX); assert(colour != NULL_COLOUR); } @@ -40,6 +38,18 @@ Province::life_rating_t Province::get_life_rating() const { return life_rating; } +return_t Province::add_building(BuildingType const& type) { + return buildings.add_item({ type }); +} + +void Province::lock_buildings() { + buildings.lock(false); +} + +void Province::reset_buildings() { + buildings.reset(); +} + std::vector const& Province::get_buildings() const { return buildings.get_items(); } diff --git a/extension/src/openvic2/map/Province.hpp b/extension/src/openvic2/map/Province.hpp index 0b7cd4c..aa0329c 100644 --- a/extension/src/openvic2/map/Province.hpp +++ b/extension/src/openvic2/map/Province.hpp @@ -19,23 +19,27 @@ namespace OpenVic2 { static constexpr colour_t NULL_COLOUR = 0, MAX_COLOUR = 0xFFFFFF; static constexpr index_t NULL_INDEX = 0, MAX_INDEX = 0xFFFF; private: - index_t index; - colour_t colour; + const index_t index; + const colour_t colour; Region* region = nullptr; bool water = false; life_rating_t life_rating = 0; - static const char buildings_name[]; - IdentifierRegistry buildings; + IdentifierRegistry buildings; Province(index_t new_index, std::string const& new_identifier, colour_t new_colour); public: static std::string colour_to_hex_string(colour_t colour); + Province(Province&&) = default; + index_t get_index() const; colour_t get_colour() const; Region* get_region() const; bool is_water() const; life_rating_t get_life_rating() const; + return_t add_building(BuildingType const& type); + void lock_buildings(); + void reset_buildings(); std::vector const& get_buildings() const; return_t expand_building(std::string const& building_type_identifier); std::string to_string() const; diff --git a/extension/src/openvic2/map/Region.hpp b/extension/src/openvic2/map/Region.hpp index 2eec1cd..04564fc 100644 --- a/extension/src/openvic2/map/Region.hpp +++ b/extension/src/openvic2/map/Region.hpp @@ -23,6 +23,8 @@ namespace OpenVic2 { private: Region(std::string const& new_identifier); public: + Region(Region&&) = default; + Province::colour_t get_colour() const; }; } diff --git a/game/src/Autoload/Events.gd b/game/src/Autoload/Events.gd index 0ee2eff..7540d3e 100644 --- a/game/src/Autoload/Events.gd +++ b/game/src/Autoload/Events.gd @@ -19,4 +19,3 @@ func _ready(): push_error("Failed to load regions") if GameSingleton.load_province_shape_file(_province_shape_file) != OK: push_error("Failed to load province shapes") - GameSingleton.finished_loading_data() diff --git a/game/src/GameSession/GameSession.gd b/game/src/GameSession/GameSession.gd index 2761815..556b98e 100644 --- a/game/src/GameSession/GameSession.gd +++ b/game/src/GameSession/GameSession.gd @@ -4,6 +4,8 @@ extends Control func _ready(): Events.Options.load_settings_from_file() + if GameSingleton.setup() != OK: + push_error("Failed to setup game") func _process(delta : float): GameSingleton.try_tick() diff --git a/game/src/GameSession/GameSessionMenu.gd b/game/src/GameSession/GameSessionMenu.gd index 70a1630..6f373d7 100644 --- a/game/src/GameSession/GameSessionMenu.gd +++ b/game/src/GameSession/GameSessionMenu.gd @@ -45,7 +45,6 @@ func show_save_dialog_button() -> void: # * SS-47 # * UIFUN-69 func _on_main_menu_confirmed() -> void: - # TODO - reset map when going back to main menu get_tree().change_scene_to_packed(_main_menu_scene) # REQUIREMENTS: -- cgit v1.2.3-56-ga3b1 From 563834e7e6f9ce565bbfd553a0d9ff80a98c677d Mon Sep 17 00:00:00 2001 From: Hop311 Date: Tue, 25 Apr 2023 23:51:44 +0100 Subject: Divide map texture to fit in 16384 GPU dim limit --- extension/src/GameSingleton.cpp | 40 +++++++++++++++++++++----------- extension/src/GameSingleton.hpp | 5 ++-- extension/src/openvic2/Types.hpp | 3 +++ game/src/GameSession/MapView.gd | 12 ++++++---- game/src/GameSession/TerrainMap.gdshader | 23 ++++++++---------- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/extension/src/GameSingleton.cpp b/extension/src/GameSingleton.cpp index 32d940c..3811dea 100644 --- a/extension/src/GameSingleton.cpp +++ b/extension/src/GameSingleton.cpp @@ -24,7 +24,7 @@ void GameSingleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_province_info_from_index", "index"), &GameSingleton::get_province_info_from_index); ClassDB::bind_method(D_METHOD("get_width"), &GameSingleton::get_width); ClassDB::bind_method(D_METHOD("get_height"), &GameSingleton::get_height); - ClassDB::bind_method(D_METHOD("get_province_index_image"), &GameSingleton::get_province_index_image); + ClassDB::bind_method(D_METHOD("get_province_index_images"), &GameSingleton::get_province_index_images); ClassDB::bind_method(D_METHOD("get_province_colour_image"), &GameSingleton::get_province_colour_image); ClassDB::bind_method(D_METHOD("update_colour_image"), &GameSingleton::update_colour_image); @@ -231,7 +231,7 @@ Error GameSingleton::load_region_file(String const& file_path) { } Error GameSingleton::load_province_shape_file(String const& file_path) { - if (province_index_image.is_valid()) { + if (province_index_image[0].is_valid()) { UtilityFunctions::push_error("Province shape file has already been loaded, cannot load: ", file_path); return FAILED; } @@ -242,12 +242,16 @@ Error GameSingleton::load_province_shape_file(String const& file_path) { UtilityFunctions::push_error("Failed to load province shape file: ", file_path); return err; } - int32_t width = province_shape_image->get_width(); - int32_t height = province_shape_image->get_height(); + const int32_t width = province_shape_image->get_width(); + const int32_t height = province_shape_image->get_height(); if (width < 1 || height < 1) { UtilityFunctions::push_error("Invalid dimensions (", width, "x", height, ") for province shape file: ", file_path); err = FAILED; } + if (width % image_width_divide != 0) { + UtilityFunctions::push_error("Invalid width ", width, " (must be divisible by ", image_width_divide, ") for province shape file: ", file_path); + err = FAILED; + } static constexpr Image::Format expected_format = Image::FORMAT_RGB8; const Image::Format format = province_shape_image->get_format(); if (format != expected_format) { @@ -257,15 +261,20 @@ Error GameSingleton::load_province_shape_file(String const& file_path) { if (err != OK) return err; err = ERR(game_manager.map.generate_province_index_image(width, height, province_shape_image->get_data().ptr())); - PackedByteArray index_data_array; - index_data_array.resize(width * height * sizeof(Province::index_t)); std::vector const& province_index_data = game_manager.map.get_province_index_image(); - memcpy(index_data_array.ptrw(), province_index_data.data(), province_index_data.size()); - - province_index_image = Image::create_from_data(width, height, false, Image::FORMAT_RG8, index_data_array); - if (province_index_image.is_null()) { - UtilityFunctions::push_error("Failed to create province ID image"); - err = FAILED; + const int32_t divided_width = width / image_width_divide; + for (int32_t i = 0; i < image_width_divide; ++i) { + PackedByteArray index_data_array; + index_data_array.resize(divided_width * height * sizeof(Province::index_t)); + for (int32_t y = 0; y < height; ++y) + memcpy(index_data_array.ptrw() + y * divided_width * sizeof(Province::index_t), + province_index_data.data() + y * width + i * divided_width, + divided_width * sizeof(Province::index_t)); + province_index_image[i] = Image::create_from_data(divided_width, height, false, Image::FORMAT_RG8, index_data_array); + if (province_index_image[i].is_null()) { + UtilityFunctions::push_error("Failed to create province ID image #", i); + err = FAILED; + } } if (update_colour_image() != OK) err = FAILED; @@ -357,8 +366,11 @@ int32_t GameSingleton::get_height() const { return game_manager.map.get_height(); } -Ref GameSingleton::get_province_index_image() const { - return province_index_image; +Array GameSingleton::get_province_index_images() const { + Array ret; + for (int i = 0; i < image_width_divide; ++i) + ret.append(province_index_image[i]); + return ret; } Ref GameSingleton::get_province_colour_image() const { diff --git a/extension/src/GameSingleton.hpp b/extension/src/GameSingleton.hpp index 815c92f..d9879ef 100644 --- a/extension/src/GameSingleton.hpp +++ b/extension/src/GameSingleton.hpp @@ -14,7 +14,8 @@ namespace OpenVic2 { GameManager game_manager; - godot::Ref province_index_image, province_colour_image; + static constexpr int image_width_divide = 2; + godot::Ref province_index_image[image_width_divide], province_colour_image; Mapmode::index_t mapmode_index = 0; godot::Error _parse_province_identifier_entry(godot::String const& identifier, godot::Variant const& entry); @@ -39,7 +40,7 @@ namespace OpenVic2 { godot::Dictionary get_province_info_from_index(int32_t index) const; int32_t get_width() const; int32_t get_height() const; - godot::Ref get_province_index_image() const; + godot::Array get_province_index_images() const; godot::Ref get_province_colour_image() const; godot::Error update_colour_image(); diff --git a/extension/src/openvic2/Types.hpp b/extension/src/openvic2/Types.hpp index f53f842..98e92ce 100644 --- a/extension/src/openvic2/Types.hpp +++ b/extension/src/openvic2/Types.hpp @@ -22,6 +22,9 @@ namespace OpenVic2 { public: HasIdentifier(HasIdentifier const&) = delete; HasIdentifier(HasIdentifier&&) = default; + HasIdentifier& operator=(HasIdentifier const&) = delete; + HasIdentifier& operator=(HasIdentifier&&) = delete; + std::string const& get_identifier() const; }; diff --git a/game/src/GameSession/MapView.gd b/game/src/GameSession/MapView.gd index 510d70a..e74ea59 100644 --- a/game/src/GameSession/MapView.gd +++ b/game/src/GameSession/MapView.gd @@ -41,7 +41,6 @@ var _mouse_over_viewport : bool = true var _map_mesh : MapMesh var _map_shader_material : ShaderMaterial var _map_image_size : Vector2 -var _map_province_index_image : Image var _map_province_colour_image : Image var _map_province_colour_texture : ImageTexture var _map_mesh_corner : Vector2 @@ -77,12 +76,15 @@ func _ready(): return _map_shader_material = map_material - # Province index texture - _map_province_index_image = GameSingleton.get_province_index_image() - if _map_province_index_image == null: + # Province index textures + var map_province_index_images := GameSingleton.get_province_index_images() + if map_province_index_images == null or map_province_index_images.is_empty(): push_error("Failed to get province index image!") return - var province_index_texture := ImageTexture.create_from_image(_map_province_index_image) + var province_index_texture := Texture2DArray.new() + if province_index_texture.create_from_images(map_province_index_images) != OK: + push_error("Failed to generate province index texture array!") + return _map_shader_material.set_shader_parameter(_shader_param_province_index, province_index_texture) # Province colour texture diff --git a/game/src/GameSession/TerrainMap.gdshader b/game/src/GameSession/TerrainMap.gdshader index 9ce1a24..305a34b 100644 --- a/game/src/GameSession/TerrainMap.gdshader +++ b/game/src/GameSession/TerrainMap.gdshader @@ -5,7 +5,7 @@ render_mode unshaded; // Cosmetic farmlands terrain texture uniform sampler2D farmlands_tex: source_color, repeat_enable, filter_linear; // Province index texture -uniform sampler2D province_index_tex : source_color, repeat_enable, filter_nearest; +uniform sampler2DArray province_index_tex : source_color, repeat_enable, filter_nearest; // Province colour texture uniform sampler2D province_colour_tex: source_color, repeat_enable, filter_nearest; // Index of the mouse over the map mesh @@ -18,23 +18,20 @@ uniform float terrain_tile_factor; uvec2 vec2_to_uvec2(vec2 v) { return uvec2(v * 255.0); } - +uvec2 read_uvec2(vec2 uv) { + float width_divisions = float(textureSize(province_index_tex, 0).z); + uv.x *= width_divisions; + float idx = mod(floor(uv.x), width_divisions); + return vec2_to_uvec2(texture(province_index_tex, vec3(uv, idx)).rg); +} uint uvec2_to_uint(uvec2 v) { return (v.y << 8u) | v.x; } -uvec2 read_uvec2(sampler2D tex, vec2 uv) { - return vec2_to_uvec2(texture(tex, uv).rg); -} - -uint read_uint16(sampler2D tex, vec2 uv) { - return uvec2_to_uint(read_uvec2(tex, uv)); -} - const vec3 water_colour = vec3(0, 0, 1); vec3 get_terrain_colour(vec2 uv, vec2 corner, vec2 half_pixel_size, vec2 terrain_uv) { - uvec2 index_split = read_uvec2(province_index_tex, fma(corner, half_pixel_size, uv)); + uvec2 index_split = read_uvec2(fma(corner, half_pixel_size, uv)); uint index = uvec2_to_uint(index_split); vec4 province_data = texelFetch(province_colour_tex, ivec2(index_split), 0); vec3 province_colour = province_data.rgb; @@ -47,8 +44,8 @@ vec3 get_terrain_colour(vec2 uv, vec2 corner, vec2 half_pixel_size, vec2 terrain } vec3 mix_terrain_colour(vec2 uv) { - vec2 map_size = vec2(textureSize(province_index_tex, 0)); - vec2 pixel_offset = mod(fma(uv, map_size, vec2(0.5)), 1.0); + vec2 map_size = vec2(textureSize(province_index_tex, 0).xy); + vec2 pixel_offset = fract(fma(uv, map_size, vec2(0.5))); vec2 half_pixel_size = 0.49 / map_size; vec2 terrain_uv = uv; -- cgit v1.2.3-56-ga3b1