diff --git a/artifacts/alien_research.png b/artifacts/alien_research.png new file mode 100644 index 0000000..1f58eca Binary files /dev/null and b/artifacts/alien_research.png differ diff --git a/artifacts/alien_research.png.import b/artifacts/alien_research.png.import new file mode 100644 index 0000000..4d7875e --- /dev/null +++ b/artifacts/alien_research.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yaanw684l0dn" +path="res://.godot/imported/alien_research.png-c2267e9526abcbb04057176fbe27db67.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/alien_research.png" +dest_files=["res://.godot/imported/alien_research.png-c2267e9526abcbb04057176fbe27db67.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/alien_research_hover.png b/artifacts/alien_research_hover.png new file mode 100644 index 0000000..76e037b Binary files /dev/null and b/artifacts/alien_research_hover.png differ diff --git a/artifacts/alien_research_hover.png.import b/artifacts/alien_research_hover.png.import new file mode 100644 index 0000000..fc0fd9f --- /dev/null +++ b/artifacts/alien_research_hover.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mer8ums08nx6" +path="res://.godot/imported/alien_research_hover.png-4de51699f2d0fe2e1497f484fc622833.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/alien_research_hover.png" +dest_files=["res://.godot/imported/alien_research_hover.png-4de51699f2d0fe2e1497f484fc622833.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/captain_ring_hud.png b/artifacts/captain_ring_hud.png new file mode 100644 index 0000000..74f4ffd Binary files /dev/null and b/artifacts/captain_ring_hud.png differ diff --git a/artifacts/captain_ring_hud.png.import b/artifacts/captain_ring_hud.png.import new file mode 100644 index 0000000..80473d0 --- /dev/null +++ b/artifacts/captain_ring_hud.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bemu3i86nj77c" +path="res://.godot/imported/captain_ring_hud.png-35fde23680f1e2d0ff8ec4cbe1858433.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/captain_ring_hud.png" +dest_files=["res://.godot/imported/captain_ring_hud.png-35fde23680f1e2d0ff8ec4cbe1858433.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/captain_ring_panel.png b/artifacts/captain_ring_panel.png new file mode 100644 index 0000000..24139cf Binary files /dev/null and b/artifacts/captain_ring_panel.png differ diff --git a/artifacts/captain_ring_panel.png.import b/artifacts/captain_ring_panel.png.import new file mode 100644 index 0000000..85d04c1 --- /dev/null +++ b/artifacts/captain_ring_panel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://q1m5u45ej5t2" +path="res://.godot/imported/captain_ring_panel.png-6c4e3257af40d53e47acf7e173bddb3a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/captain_ring_panel.png" +dest_files=["res://.godot/imported/captain_ring_panel.png-6c4e3257af40d53e47acf7e173bddb3a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/cockpit_console_1280x720.png b/artifacts/cockpit_console_1280x720.png new file mode 100644 index 0000000..fa3249f Binary files /dev/null and b/artifacts/cockpit_console_1280x720.png differ diff --git a/artifacts/cockpit_console_1280x720.png.import b/artifacts/cockpit_console_1280x720.png.import new file mode 100644 index 0000000..44a8c65 --- /dev/null +++ b/artifacts/cockpit_console_1280x720.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jwmwu6gevn8j" +path="res://.godot/imported/cockpit_console_1280x720.png-4159f616d7b3d83d1955aedf8eedd32a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/cockpit_console_1280x720.png" +dest_files=["res://.godot/imported/cockpit_console_1280x720.png-4159f616d7b3d83d1955aedf8eedd32a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/cockpit_console_800x600.png b/artifacts/cockpit_console_800x600.png new file mode 100644 index 0000000..9f7af62 Binary files /dev/null and b/artifacts/cockpit_console_800x600.png differ diff --git a/artifacts/cockpit_console_800x600.png.import b/artifacts/cockpit_console_800x600.png.import new file mode 100644 index 0000000..4817827 --- /dev/null +++ b/artifacts/cockpit_console_800x600.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c38plrli4ya25" +path="res://.godot/imported/cockpit_console_800x600.png-33aefb0a6fac6f21b0d22c38af5a3e7d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/cockpit_console_800x600.png" +dest_files=["res://.godot/imported/cockpit_console_800x600.png-33aefb0a6fac6f21b0d22c38af5a3e7d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/cockpit_console_960x540.png b/artifacts/cockpit_console_960x540.png new file mode 100644 index 0000000..a7b7267 Binary files /dev/null and b/artifacts/cockpit_console_960x540.png differ diff --git a/artifacts/cockpit_console_960x540.png.import b/artifacts/cockpit_console_960x540.png.import new file mode 100644 index 0000000..afb0c25 --- /dev/null +++ b/artifacts/cockpit_console_960x540.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0bfcmpc4srcs" +path="res://.godot/imported/cockpit_console_960x540.png-d012e49e82ff0ca3dc072545b6ac39be.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/cockpit_console_960x540.png" +dest_files=["res://.godot/imported/cockpit_console_960x540.png-d012e49e82ff0ca3dc072545b6ac39be.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/cockpit_console_review.png b/artifacts/cockpit_console_review.png new file mode 100644 index 0000000..2473b77 Binary files /dev/null and b/artifacts/cockpit_console_review.png differ diff --git a/artifacts/cockpit_console_review.png.import b/artifacts/cockpit_console_review.png.import new file mode 100644 index 0000000..1deced4 --- /dev/null +++ b/artifacts/cockpit_console_review.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dgj1s0l4v8j8i" +path="res://.godot/imported/cockpit_console_review.png-46f00c5f242ff57946c4788f05de278c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/cockpit_console_review.png" +dest_files=["res://.godot/imported/cockpit_console_review.png-46f00c5f242ff57946c4788f05de278c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/cockpit_frame_review.png b/artifacts/cockpit_frame_review.png new file mode 100644 index 0000000..87cb3aa Binary files /dev/null and b/artifacts/cockpit_frame_review.png differ diff --git a/artifacts/cockpit_frame_review.png.import b/artifacts/cockpit_frame_review.png.import new file mode 100644 index 0000000..3fa51d6 --- /dev/null +++ b/artifacts/cockpit_frame_review.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj748ga2lns7g" +path="res://.godot/imported/cockpit_frame_review.png-6fb52f5726eaf410eb48ac602d5fe727.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/cockpit_frame_review.png" +dest_files=["res://.godot/imported/cockpit_frame_review.png-6fb52f5726eaf410eb48ac602d5fe727.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/compact_interface_freighter.png b/artifacts/compact_interface_freighter.png new file mode 100644 index 0000000..31c19cc Binary files /dev/null and b/artifacts/compact_interface_freighter.png differ diff --git a/artifacts/compact_interface_freighter.png.import b/artifacts/compact_interface_freighter.png.import new file mode 100644 index 0000000..e7faefb --- /dev/null +++ b/artifacts/compact_interface_freighter.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://04ftf2um02y8" +path="res://.godot/imported/compact_interface_freighter.png-63e4282514047b8948ebb564b5646054.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/compact_interface_freighter.png" +dest_files=["res://.godot/imported/compact_interface_freighter.png-63e4282514047b8948ebb564b5646054.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/compact_interface_hud.png b/artifacts/compact_interface_hud.png new file mode 100644 index 0000000..4877acc Binary files /dev/null and b/artifacts/compact_interface_hud.png differ diff --git a/artifacts/compact_interface_hud.png.import b/artifacts/compact_interface_hud.png.import new file mode 100644 index 0000000..ccf6433 --- /dev/null +++ b/artifacts/compact_interface_hud.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bci3mu5kg4351" +path="res://.godot/imported/compact_interface_hud.png-ea1968de19ced1671f28f4a62a6a4760.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/compact_interface_hud.png" +dest_files=["res://.godot/imported/compact_interface_hud.png-ea1968de19ced1671f28f4a62a6a4760.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/compact_interface_research.png b/artifacts/compact_interface_research.png new file mode 100644 index 0000000..8e6916d Binary files /dev/null and b/artifacts/compact_interface_research.png differ diff --git a/artifacts/compact_interface_research.png.import b/artifacts/compact_interface_research.png.import new file mode 100644 index 0000000..43a062b --- /dev/null +++ b/artifacts/compact_interface_research.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cemfvsvogbbaq" +path="res://.godot/imported/compact_interface_research.png-0ef8d849edcfaca3c9c65149cd695b1f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/compact_interface_research.png" +dest_files=["res://.godot/imported/compact_interface_research.png-0ef8d849edcfaca3c9c65149cd695b1f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/compact_interface_skills.png b/artifacts/compact_interface_skills.png new file mode 100644 index 0000000..af9a10d Binary files /dev/null and b/artifacts/compact_interface_skills.png differ diff --git a/artifacts/compact_interface_skills.png.import b/artifacts/compact_interface_skills.png.import new file mode 100644 index 0000000..d04b762 --- /dev/null +++ b/artifacts/compact_interface_skills.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmt818jkr2vvl" +path="res://.godot/imported/compact_interface_skills.png-1a40c0e58cdcf846826c1e074eae7d87.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/compact_interface_skills.png" +dest_files=["res://.godot/imported/compact_interface_skills.png-1a40c0e58cdcf846826c1e074eae7d87.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/construction_layout_fixed.png b/artifacts/construction_layout_fixed.png new file mode 100644 index 0000000..59bf22d Binary files /dev/null and b/artifacts/construction_layout_fixed.png differ diff --git a/artifacts/construction_layout_fixed.png.import b/artifacts/construction_layout_fixed.png.import new file mode 100644 index 0000000..81df3e4 --- /dev/null +++ b/artifacts/construction_layout_fixed.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dijaq6dht4obx" +path="res://.godot/imported/construction_layout_fixed.png-d148f2716c8d2dbd431b6294b6c5e3d1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/construction_layout_fixed.png" +dest_files=["res://.godot/imported/construction_layout_fixed.png-d148f2716c8d2dbd431b6294b6c5e3d1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/hangar_slot_unlock.png b/artifacts/hangar_slot_unlock.png index 3b9ca48..20b5eae 100644 Binary files a/artifacts/hangar_slot_unlock.png and b/artifacts/hangar_slot_unlock.png differ diff --git a/artifacts/ship_hud.png b/artifacts/ship_hud.png new file mode 100644 index 0000000..141bffa Binary files /dev/null and b/artifacts/ship_hud.png differ diff --git a/artifacts/ship_hud.png.import b/artifacts/ship_hud.png.import new file mode 100644 index 0000000..50f3e5c --- /dev/null +++ b/artifacts/ship_hud.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0ucpvf7esi88" +path="res://.godot/imported/ship_hud.png-f68d075fba20b3f70ef34f129a94d9e2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_hud.png" +dest_files=["res://.godot/imported/ship_hud.png-f68d075fba20b3f70ef34f129a94d9e2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/ship_ring_panel.png b/artifacts/ship_ring_panel.png new file mode 100644 index 0000000..b821021 Binary files /dev/null and b/artifacts/ship_ring_panel.png differ diff --git a/artifacts/ship_ring_panel.png.import b/artifacts/ship_ring_panel.png.import new file mode 100644 index 0000000..bbfbe7b --- /dev/null +++ b/artifacts/ship_ring_panel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhwqqvn3wjn0l" +path="res://.godot/imported/ship_ring_panel.png-434b4e9ab6edb953c2f703fa5c7c90d2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_ring_panel.png" +dest_files=["res://.godot/imported/ship_ring_panel.png-434b4e9ab6edb953c2f703fa5c7c90d2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/ship_statistics_parameters.png b/artifacts/ship_statistics_parameters.png new file mode 100644 index 0000000..62872fa Binary files /dev/null and b/artifacts/ship_statistics_parameters.png differ diff --git a/artifacts/ship_statistics_parameters.png.import b/artifacts/ship_statistics_parameters.png.import new file mode 100644 index 0000000..136529d --- /dev/null +++ b/artifacts/ship_statistics_parameters.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c8u0n52jkd8ft" +path="res://.godot/imported/ship_statistics_parameters.png-33c84b9c0fb769b343bfb66d8987e370.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_statistics_parameters.png" +dest_files=["res://.godot/imported/ship_statistics_parameters.png-33c84b9c0fb769b343bfb66d8987e370.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/ship_statistics_systems.png b/artifacts/ship_statistics_systems.png new file mode 100644 index 0000000..557adf5 Binary files /dev/null and b/artifacts/ship_statistics_systems.png differ diff --git a/artifacts/ship_statistics_systems.png.import b/artifacts/ship_statistics_systems.png.import new file mode 100644 index 0000000..5c66534 --- /dev/null +++ b/artifacts/ship_statistics_systems.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caq1xtutwj5sj" +path="res://.godot/imported/ship_statistics_systems.png-d708e0872dfc181522107a8c5a97a3a2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_statistics_systems.png" +dest_files=["res://.godot/imported/ship_statistics_systems.png-d708e0872dfc181522107a8c5a97a3a2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/ship_statistics_weapons.png b/artifacts/ship_statistics_weapons.png new file mode 100644 index 0000000..8af19c5 Binary files /dev/null and b/artifacts/ship_statistics_weapons.png differ diff --git a/artifacts/ship_statistics_weapons.png.import b/artifacts/ship_statistics_weapons.png.import new file mode 100644 index 0000000..4959630 --- /dev/null +++ b/artifacts/ship_statistics_weapons.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8glniut4pkvv" +path="res://.godot/imported/ship_statistics_weapons.png-1cadf69d9d627a4573b6e7c8826b0144.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_statistics_weapons.png" +dest_files=["res://.godot/imported/ship_statistics_weapons.png-1cadf69d9d627a4573b6e7c8826b0144.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/ship_status_frame_review.png b/artifacts/ship_status_frame_review.png new file mode 100644 index 0000000..14570a5 Binary files /dev/null and b/artifacts/ship_status_frame_review.png differ diff --git a/artifacts/ship_status_frame_review.png.import b/artifacts/ship_status_frame_review.png.import new file mode 100644 index 0000000..2cf7e00 --- /dev/null +++ b/artifacts/ship_status_frame_review.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqnftyve0ob42" +path="res://.godot/imported/ship_status_frame_review.png-b310039c865b152de525bcf598d930e9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/ship_status_frame_review.png" +dest_files=["res://.godot/imported/ship_status_frame_review.png-b310039c865b152de525bcf598d930e9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_blizzard.png b/artifacts/weather_condition_blizzard.png new file mode 100644 index 0000000..3fb9b29 Binary files /dev/null and b/artifacts/weather_condition_blizzard.png differ diff --git a/artifacts/weather_condition_blizzard.png.import b/artifacts/weather_condition_blizzard.png.import new file mode 100644 index 0000000..6492a18 --- /dev/null +++ b/artifacts/weather_condition_blizzard.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nxg6odgt1nct" +path="res://.godot/imported/weather_condition_blizzard.png-5a2e079ff8ef2f240d3fd9f382e0bb3c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_blizzard.png" +dest_files=["res://.godot/imported/weather_condition_blizzard.png-5a2e079ff8ef2f240d3fd9f382e0bb3c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_clear.png b/artifacts/weather_condition_clear.png new file mode 100644 index 0000000..7794f4d Binary files /dev/null and b/artifacts/weather_condition_clear.png differ diff --git a/artifacts/weather_condition_clear.png.import b/artifacts/weather_condition_clear.png.import new file mode 100644 index 0000000..bac3d59 --- /dev/null +++ b/artifacts/weather_condition_clear.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://po6k1mi1l88v" +path="res://.godot/imported/weather_condition_clear.png-442ce1ce92b5588777307fba12c6f7a4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_clear.png" +dest_files=["res://.godot/imported/weather_condition_clear.png-442ce1ce92b5588777307fba12c6f7a4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_cloudy.png b/artifacts/weather_condition_cloudy.png new file mode 100644 index 0000000..9c0c617 Binary files /dev/null and b/artifacts/weather_condition_cloudy.png differ diff --git a/artifacts/weather_condition_cloudy.png.import b/artifacts/weather_condition_cloudy.png.import new file mode 100644 index 0000000..4eabf26 --- /dev/null +++ b/artifacts/weather_condition_cloudy.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://p6413fvq1165" +path="res://.godot/imported/weather_condition_cloudy.png-09ef77e56bff84e3873fefc1fcb536d5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_cloudy.png" +dest_files=["res://.godot/imported/weather_condition_cloudy.png-09ef77e56bff84e3873fefc1fcb536d5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_dust_storm.png b/artifacts/weather_condition_dust_storm.png new file mode 100644 index 0000000..3e5ca82 Binary files /dev/null and b/artifacts/weather_condition_dust_storm.png differ diff --git a/artifacts/weather_condition_dust_storm.png.import b/artifacts/weather_condition_dust_storm.png.import new file mode 100644 index 0000000..a8ddac8 --- /dev/null +++ b/artifacts/weather_condition_dust_storm.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crtykmxtfw0ls" +path="res://.godot/imported/weather_condition_dust_storm.png-cd593b6234ba283f042805ff46e91dbb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_dust_storm.png" +dest_files=["res://.godot/imported/weather_condition_dust_storm.png-cd593b6234ba283f042805ff46e91dbb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_fog.png b/artifacts/weather_condition_fog.png new file mode 100644 index 0000000..e2fd626 Binary files /dev/null and b/artifacts/weather_condition_fog.png differ diff --git a/artifacts/weather_condition_fog.png.import b/artifacts/weather_condition_fog.png.import new file mode 100644 index 0000000..386c4ff --- /dev/null +++ b/artifacts/weather_condition_fog.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://iuxgw4bqk8kh" +path="res://.godot/imported/weather_condition_fog.png-0c94c5dc380f0056245c595c7217825c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_fog.png" +dest_files=["res://.godot/imported/weather_condition_fog.png-0c94c5dc380f0056245c595c7217825c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_overcast.png b/artifacts/weather_condition_overcast.png new file mode 100644 index 0000000..cc8acc1 Binary files /dev/null and b/artifacts/weather_condition_overcast.png differ diff --git a/artifacts/weather_condition_overcast.png.import b/artifacts/weather_condition_overcast.png.import new file mode 100644 index 0000000..dff7c06 --- /dev/null +++ b/artifacts/weather_condition_overcast.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byljypcneg24r" +path="res://.godot/imported/weather_condition_overcast.png-a64472efc3e7dc5213e96d4f03f6b641.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_overcast.png" +dest_files=["res://.godot/imported/weather_condition_overcast.png-a64472efc3e7dc5213e96d4f03f6b641.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_rain.png b/artifacts/weather_condition_rain.png new file mode 100644 index 0000000..49d9f5b Binary files /dev/null and b/artifacts/weather_condition_rain.png differ diff --git a/artifacts/weather_condition_rain.png.import b/artifacts/weather_condition_rain.png.import new file mode 100644 index 0000000..181a579 --- /dev/null +++ b/artifacts/weather_condition_rain.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brcug5gbejyy0" +path="res://.godot/imported/weather_condition_rain.png-0153c99b79715b7df54f07b0bc60996b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_rain.png" +dest_files=["res://.godot/imported/weather_condition_rain.png-0153c99b79715b7df54f07b0bc60996b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_snow.png b/artifacts/weather_condition_snow.png new file mode 100644 index 0000000..67bb4f3 Binary files /dev/null and b/artifacts/weather_condition_snow.png differ diff --git a/artifacts/weather_condition_snow.png.import b/artifacts/weather_condition_snow.png.import new file mode 100644 index 0000000..164b12e --- /dev/null +++ b/artifacts/weather_condition_snow.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dic4rrua8i7pm" +path="res://.godot/imported/weather_condition_snow.png-2e06d06d4528d22977c549398ed2c082.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_snow.png" +dest_files=["res://.godot/imported/weather_condition_snow.png-2e06d06d4528d22977c549398ed2c082.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_condition_storm.png b/artifacts/weather_condition_storm.png new file mode 100644 index 0000000..9d5967c Binary files /dev/null and b/artifacts/weather_condition_storm.png differ diff --git a/artifacts/weather_condition_storm.png.import b/artifacts/weather_condition_storm.png.import new file mode 100644 index 0000000..983e886 --- /dev/null +++ b/artifacts/weather_condition_storm.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bma7pwvovri0e" +path="res://.godot/imported/weather_condition_storm.png-d042e690c08fae4b3b638d7439ce1349.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_condition_storm.png" +dest_files=["res://.godot/imported/weather_condition_storm.png-d042e690c08fae4b3b638d7439ce1349.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/artifacts/weather_conditions_review.png b/artifacts/weather_conditions_review.png new file mode 100644 index 0000000..b7cd8b8 Binary files /dev/null and b/artifacts/weather_conditions_review.png differ diff --git a/artifacts/weather_conditions_review.png.import b/artifacts/weather_conditions_review.png.import new file mode 100644 index 0000000..6510c1f --- /dev/null +++ b/artifacts/weather_conditions_review.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqwwaitp40aoo" +path="res://.godot/imported/weather_conditions_review.png-da82db891609dafef041eb57dfebbbe0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/weather_conditions_review.png" +dest_files=["res://.godot/imported/weather_conditions_review.png-da82db891609dafef041eb57dfebbbe0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/freighter/research/PROMPTS.txt b/assets/freighter/research/PROMPTS.txt new file mode 100644 index 0000000..f689f7d --- /dev/null +++ b/assets/freighter/research/PROMPTS.txt @@ -0,0 +1,12 @@ +Research icons +============== +Generated with the built-in image_gen tool; transparent PNG assets. + +Shared prompt: +Use case: stylized-concept. Asset type: a single polished sci-fi research skill icon for a compact spaceship game UI. Subject: [subject]. Painterly realistic 3D game inventory illustration, crisp strong silhouette readable at 48 pixels. Centered object fills 75 percent of square canvas, isolated on a completely transparent background. Industrial worn metal, subtle edge highlights, elegant restrained glow. No text, no letters, no border, no card, no scenery. + +Subjects: +- general.png: a luminous amber alien DNA helix suspended within a scientific scanning ring +- weapons.png: a compact alien plasma cannon, dark gunmetal with restrained copper orange energy core +- hull.png: three overlapping angular alien spacecraft armor plates, brushed dark titanium with sage green illuminated seams +- shields.png: an alien energy shield emitter, a small metallic core projecting a translucent icy cyan shield diff --git a/assets/freighter/research/general.png b/assets/freighter/research/general.png new file mode 100644 index 0000000..9a3ced6 Binary files /dev/null and b/assets/freighter/research/general.png differ diff --git a/assets/freighter/research/general.png.import b/assets/freighter/research/general.png.import new file mode 100644 index 0000000..3b8bb48 --- /dev/null +++ b/assets/freighter/research/general.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b1b35q555n78k" +path="res://.godot/imported/general.png-9899f4cbd8b1d7fd9d9e5c4dc5af5a1d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/research/general.png" +dest_files=["res://.godot/imported/general.png-9899f4cbd8b1d7fd9d9e5c4dc5af5a1d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/freighter/research/hull.png b/assets/freighter/research/hull.png new file mode 100644 index 0000000..0d78519 Binary files /dev/null and b/assets/freighter/research/hull.png differ diff --git a/assets/freighter/research/hull.png.import b/assets/freighter/research/hull.png.import new file mode 100644 index 0000000..84d9847 --- /dev/null +++ b/assets/freighter/research/hull.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duttf5uohucra" +path="res://.godot/imported/hull.png-be89bd87a1ff670817920fd7b1abca3e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/research/hull.png" +dest_files=["res://.godot/imported/hull.png-be89bd87a1ff670817920fd7b1abca3e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/freighter/research/shields.png b/assets/freighter/research/shields.png new file mode 100644 index 0000000..c60b46a Binary files /dev/null and b/assets/freighter/research/shields.png differ diff --git a/assets/freighter/research/shields.png.import b/assets/freighter/research/shields.png.import new file mode 100644 index 0000000..20edb35 --- /dev/null +++ b/assets/freighter/research/shields.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0h62slv8erwu" +path="res://.godot/imported/shields.png-5eef00a7dbe9cbe3e3bf615da34e9c38.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/research/shields.png" +dest_files=["res://.godot/imported/shields.png-5eef00a7dbe9cbe3e3bf615da34e9c38.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/freighter/research/weapons.png b/assets/freighter/research/weapons.png new file mode 100644 index 0000000..2580bb9 Binary files /dev/null and b/assets/freighter/research/weapons.png differ diff --git a/assets/freighter/research/weapons.png.import b/assets/freighter/research/weapons.png.import new file mode 100644 index 0000000..1fe745f --- /dev/null +++ b/assets/freighter/research/weapons.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://orumcop8k4v8" +path="res://.godot/imported/weapons.png-635208432e6f1db62ed8924b096f700f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/research/weapons.png" +dest_files=["res://.godot/imported/weapons.png-635208432e6f1db62ed8924b096f700f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/PROMPT.txt b/assets/ui/frames/PROMPT.txt new file mode 100644 index 0000000..d41739f --- /dev/null +++ b/assets/ui/frames/PROMPT.txt @@ -0,0 +1,4 @@ +Generated asset: ship_ornament.png +Tool: built-in image_gen, transparent background. +Prompt: +Use case: stylized-concept. Asset type: production game UI frame texture. A single elegant horizontal rectangular spacecraft HUD frame, aspect ratio about 3:1, front view perfectly flat and axis-aligned. Thin dark gunmetal and brushed titanium rim, precision machined beveled edges, restrained teal luminous seams, tiny warm brass corner clamps. Outer frame occupies nearly entire canvas, generous completely empty transparent rectangular opening covering 85 percent of the interior. Transparent outside too. Uniform narrow border, no central crossbars, no panels inside the opening, no contents. Sophisticated industrial spaceship cockpit aesthetic, clean and readable at small UI scale. No text, no letters, no numbers, no icons, no scenery, no perspective, no drop shadow outside frame. Real transparent alpha. It will be stretched with nine-patch corners to surround live text and progress bars. diff --git a/assets/ui/frames/captain_ring_frame.PROMPT.txt b/assets/ui/frames/captain_ring_frame.PROMPT.txt new file mode 100644 index 0000000..9b5e3e9 --- /dev/null +++ b/assets/ui/frames/captain_ring_frame.PROMPT.txt @@ -0,0 +1 @@ +Use case: stylized-concept. Reference image: existing spaceship HUD asset, match its circular bezel and metal style exactly. Generate a companion CAPTAIN HUD asset with NO TEXT. Transparent production PNG, flat orthographic game UI. One circular portrait bezel on the LEFT, same brushed silver gunmetal, cyan light strips and tiny brass fasteners as reference. From its RIGHT side extends ONE horizontal rectangular information frame with empty fully transparent interior, replacing the three separate bars of the reference. Overall aspect ratio 3.4:1. Left circle diameter about 90 percent of total image height, circular opening clear and empty. Circle center x15 percent y50 percent. Rectangular information frame extends from x26 percent to x97 percent, top at y13 percent bottom y87 percent; its thin metallic rim physically joined to circle, no vertical rail through circular opening. Empty rectangle interior to hold runtime level, credits and XP. Restrained elegant fine trim, rounded beveled corners, matching the reference circle faithfully. Fully transparent interior and exterior, small outer margins. No portrait, no text, no numbers, no labels, no icons, no bars, no solid panel fill, no background, no perspective. One single connected asset, usable at 244x72 pixels. diff --git a/assets/ui/frames/captain_ring_frame.png b/assets/ui/frames/captain_ring_frame.png new file mode 100644 index 0000000..64c4f82 Binary files /dev/null and b/assets/ui/frames/captain_ring_frame.png differ diff --git a/assets/ui/frames/captain_ring_frame.png.import b/assets/ui/frames/captain_ring_frame.png.import new file mode 100644 index 0000000..83e6a56 --- /dev/null +++ b/assets/ui/frames/captain_ring_frame.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfgrqurr1lobg" +path="res://.godot/imported/captain_ring_frame.png-e4969ca664ff0ddff79942c085a55717.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/captain_ring_frame.png" +dest_files=["res://.godot/imported/captain_ring_frame.png-e4969ca664ff0ddff79942c085a55717.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/cockpit_console.PROMPT.txt b/assets/ui/frames/cockpit_console.PROMPT.txt new file mode 100644 index 0000000..c35b106 --- /dev/null +++ b/assets/ui/frames/cockpit_console.PROMPT.txt @@ -0,0 +1 @@ +Use case: stylized-concept. Production transparent PNG game HUD asset. A REAL SPACESHIP COCKPIT INSTRUMENT CONSOLE viewed straight on, orthographic front elevation, wide low dashboard silhouette aspect ratio 6:1, designed for an 850x144 pixel bottom HUD. This is NOT a decorative picture frame. Substantial functional matte charcoal titanium console body, beveled raised end pods, recessed instrument bays, screws, narrow vent grilles, small physical amber and cool white indicator lamps and tactile switches along the very bottom lip. Restrained worn industrial spacecraft realism, clean legible high quality hard-surface rendering, subtle cool blue edge lighting, no ornate brass or medieval trim. THREE clearly separated large EMPTY rectangular display openings across the dashboard: left bay from x4%-26%, center bay x29%-68%, right bay x72%-96%; all bays from y14%-83%. The screen openings must be fully transparent, as must the entire exterior around console silhouette. Keep structural separators narrow and usable openings broad. Thin top brow and bottom instrument lip with small buttons; do not obstruct openings with decorative objects. Center bay flat and wide, right and left console shoulders slightly raised. Full console visible and centered, tiny transparent margins; if canvas is taller leave transparent padding above and below the wide console. NO text, NO numbers, NO symbols, NO graphs, NO filled screens, NO holograms, NO spaceship scene, NO steering wheel, NO portrait circles, NO perspective. One polished functional cockpit dashboard sprite, all runtime information will be drawn later inside transparent display openings. diff --git a/assets/ui/frames/cockpit_console.png b/assets/ui/frames/cockpit_console.png new file mode 100644 index 0000000..16203bf Binary files /dev/null and b/assets/ui/frames/cockpit_console.png differ diff --git a/assets/ui/frames/cockpit_console.png.import b/assets/ui/frames/cockpit_console.png.import new file mode 100644 index 0000000..c185e7c --- /dev/null +++ b/assets/ui/frames/cockpit_console.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ub0pj5k7o4c8" +path="res://.godot/imported/cockpit_console.png-dbfc4ecba01fbaf2005767e07de7627a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/cockpit_console.png" +dest_files=["res://.godot/imported/cockpit_console.png-dbfc4ecba01fbaf2005767e07de7627a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/cockpit_frame.PROMPT.txt b/assets/ui/frames/cockpit_frame.PROMPT.txt new file mode 100644 index 0000000..fc0d961 --- /dev/null +++ b/assets/ui/frames/cockpit_frame.PROMPT.txt @@ -0,0 +1 @@ +Use case: stylized-concept. Reference image is the existing captain HUD frame: match its brushed gunmetal/silver material, tiny brass fasteners and thin cyan illuminated trim. Create a production transparent PNG asset for the BOTTOM spaceship cockpit HUD in the same space RPG. ONE very wide low horizontal metallic border frame, outline aspect ratio 7:1, intended to display at 850x120 pixels. It may occupy the middle band of a wider canvas with transparent padding above and below. Straight horizontal top and bottom rails, clipped beveled outer corners, small layered mechanical brackets near both ends, tiny restrained brass rivets, subtle cyan light strips. Border thickness only 4 percent of frame height on straight rails; slightly larger corners but mostly usable empty interior. Symmetrical, flat orthographic front view, crisp professional game UI sprite. ALL interior must be empty and fully transparent, ALL exterior fully transparent. No opaque panel fill, no screens, no text, no numbers, no buttons, no bars, no icons, no circles or portraits, no mockup scene, no shadows. One single continuous wide frame, not multiple frames. Elegant thin detailing that remains legible at small size. diff --git a/assets/ui/frames/cockpit_frame.png b/assets/ui/frames/cockpit_frame.png new file mode 100644 index 0000000..a55cb55 Binary files /dev/null and b/assets/ui/frames/cockpit_frame.png differ diff --git a/assets/ui/frames/cockpit_frame.png.import b/assets/ui/frames/cockpit_frame.png.import new file mode 100644 index 0000000..9d5b41a --- /dev/null +++ b/assets/ui/frames/cockpit_frame.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dyc8u3xrjsyq0" +path="res://.godot/imported/cockpit_frame.png-8481b8724221896ba87e5cab3660a708.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/cockpit_frame.png" +dest_files=["res://.godot/imported/cockpit_frame.png-8481b8724221896ba87e5cab3660a708.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/ship_ornament.png b/assets/ui/frames/ship_ornament.png new file mode 100644 index 0000000..f5eaac7 Binary files /dev/null and b/assets/ui/frames/ship_ornament.png differ diff --git a/assets/ui/frames/ship_ornament.png.import b/assets/ui/frames/ship_ornament.png.import new file mode 100644 index 0000000..cb63f91 --- /dev/null +++ b/assets/ui/frames/ship_ornament.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c48q3lbcqdj5w" +path="res://.godot/imported/ship_ornament.png-f5630c8e09c9fea8d8da68371c867e67.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/ship_ornament.png" +dest_files=["res://.godot/imported/ship_ornament.png-f5630c8e09c9fea8d8da68371c867e67.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/ship_ring_bars.PROMPT.txt b/assets/ui/frames/ship_ring_bars.PROMPT.txt new file mode 100644 index 0000000..cb970a3 --- /dev/null +++ b/assets/ui/frames/ship_ring_bars.PROMPT.txt @@ -0,0 +1 @@ +Use case: stylized-concept. Production game HUD sprite, transparent PNG. One compact spaceship status instrument: a circular portrait bezel on the RIGHT, and THREE separate slender horizontal empty status-bar housings extending from the circle to the LEFT, physically joined to its left edge. No outer rectangular frame. Flat orthographic front view, no perspective. Overall silhouette 3.1:1 width to height. Circle outer diameter 90 percent of total height, centered at x84 percent y50 percent; its inner opening fully transparent. Three bars extend from x3 percent to x74 percent at y25,50,75 percent, each housing only 9 percent of total height; dark thin metal rail borders, empty transparent interiors, generous transparent gaps between bars for runtime captions. Elegant gunmetal, brushed silver, restrained cyan illuminated lines, tiny antique brass fasteners, detailed but legible at 221x72 pixels. Rounded bar left ends, articulated metal joins into ring. Circle must remain clearly circular. Whole image exterior and all openings fully transparent. No text, no letters, no numbers, no spaceship, no icons, no filled colored meters, no solid background, no rectangular panel. One single connected game interface component, centered with small transparent margin. diff --git a/assets/ui/frames/ship_ring_bars.png b/assets/ui/frames/ship_ring_bars.png new file mode 100644 index 0000000..1610bc6 Binary files /dev/null and b/assets/ui/frames/ship_ring_bars.png differ diff --git a/assets/ui/frames/ship_ring_bars.png.import b/assets/ui/frames/ship_ring_bars.png.import new file mode 100644 index 0000000..178cc8f --- /dev/null +++ b/assets/ui/frames/ship_ring_bars.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://p5lst48is8ab" +path="res://.godot/imported/ship_ring_bars.png-6b2a16d61f0a9f468696422dd565135e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/ship_ring_bars.png" +dest_files=["res://.godot/imported/ship_ring_bars.png-6b2a16d61f0a9f468696422dd565135e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/ui/frames/ship_status_frame.PROMPT.txt b/assets/ui/frames/ship_status_frame.PROMPT.txt new file mode 100644 index 0000000..d344cb2 --- /dev/null +++ b/assets/ui/frames/ship_status_frame.PROMPT.txt @@ -0,0 +1 @@ +Use case: stylized-concept. Asset type: production transparent PNG frame for a compact spaceship status HUD in a dark space RPG. Create ONE horizontal rectangular frame, aspect ratio 3:1, straight-on flat orthographic UI asset, centered filling canvas with only a tiny outer transparent margin. Extremely thin refined gunmetal and aged silver rim with restrained pale cyan illuminated seams and tiny brass corner fittings. Beveled angular corners, subtle mechanical detailing, polished professional space game UI, crisp readable silhouette at 221 by 72 pixels. All interior area must be fully transparent and empty, as must the exterior. Border thickness about 3 percent of image height, corner fittings no larger than 10 percent of image height. Simple uninterrupted straight top and bottom rails, no large central ornaments. No text, no letters, no numbers, no bars, no ship, no background, no opaque glass, no drop shadow, no extra icons. This is a usable frame asset, not a mockup. diff --git a/assets/ui/frames/ship_status_frame.png b/assets/ui/frames/ship_status_frame.png new file mode 100644 index 0000000..cbd4d2d Binary files /dev/null and b/assets/ui/frames/ship_status_frame.png differ diff --git a/assets/ui/frames/ship_status_frame.png.import b/assets/ui/frames/ship_status_frame.png.import new file mode 100644 index 0000000..fd5dd6e --- /dev/null +++ b/assets/ui/frames/ship_status_frame.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dk24h1mt14ljs" +path="res://.godot/imported/ship_status_frame.png-2014504a9e60843ef2215bafbeaa6fdb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/ui/frames/ship_status_frame.png" +dest_files=["res://.godot/imported/ship_status_frame.png-2014504a9e60843ef2215bafbeaa6fdb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/scenes/ui/captain_panel.tscn b/scenes/ui/captain_panel.tscn index 8e3a7dd..64a731d 100644 --- a/scenes/ui/captain_panel.tscn +++ b/scenes/ui/captain_panel.tscn @@ -21,15 +21,15 @@ bg_color = Color(0.055, 0.11, 0.16, 1) bg_color = Color(0.25, 0.68, 0.85, 1) [node name="CaptainPanel" type="PanelContainer"] -custom_minimum_size = Vector2(260, 210) +custom_minimum_size = Vector2(317.2, 93.6) theme_override_styles/panel = SubResource("PanelStyle") script = ExtResource("1_panel") -[node name="Contents" type="VBoxContainer" parent="."] +[node name="Contents" type="Control" parent="."] layout_mode = 2 theme_override_constants/separation = 4 -[node name="Header" type="HBoxContainer" parent="Contents"] +[node name="Header" type="Control" parent="Contents"] layout_mode = 2 [node name="Title" type="Label" parent="Contents/Header"] @@ -56,7 +56,7 @@ theme_override_styles/background = SubResource("XPBackground") theme_override_styles/fill = SubResource("XPFill") show_percentage = false -[node name="Wallet" type="HBoxContainer" parent="Contents"] +[node name="Wallet" type="Control" parent="Contents"] layout_mode = 2 [node name="Credits" type="Label" parent="Contents/Wallet"] diff --git a/scenes/ui/planet_services_menu.tscn b/scenes/ui/planet_services_menu.tscn index 56663b1..e491717 100644 --- a/scenes/ui/planet_services_menu.tscn +++ b/scenes/ui/planet_services_menu.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"] [sub_resource type="StyleBoxFlat" id="PanelStyle"] -bg_color = Color(0.025, 0.045, 0.065, 0.94) +bg_color = Color(0.025, 0.045, 0.065, 0.48) border_width_left = 1 border_width_top = 1 border_width_right = 1 diff --git a/scenes/ui/ship_equipment_panel.tscn b/scenes/ui/ship_equipment_panel.tscn index 9d117d1..bfb3abe 100644 --- a/scenes/ui/ship_equipment_panel.tscn +++ b/scenes/ui/ship_equipment_panel.tscn @@ -4,7 +4,7 @@ [ext_resource type="PackedScene" path="res://scenes/ui/inventory_slot_view.tscn" id="2_slot"] [sub_resource type="StyleBoxFlat" id="EquipmentPanelStyle"] -bg_color = Color(0.018, 0.028, 0.043, 0.96) +bg_color = Color(0.018, 0.028, 0.043, 0.48) border_width_left = 1 border_width_top = 1 border_width_right = 1 diff --git a/scenes/ui/ship_inventory_panel.tscn b/scenes/ui/ship_inventory_panel.tscn index 06b6061..eadd61d 100644 --- a/scenes/ui/ship_inventory_panel.tscn +++ b/scenes/ui/ship_inventory_panel.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://scripts/ui/ship_inventory_panel.gd" id="1_inventory"] [sub_resource type="StyleBoxFlat" id="InventoryStyle"] -bg_color = Color(0.018, 0.045, 0.085, 0.98) +bg_color = Color(0.018, 0.045, 0.085, 0.48) border_width_left = 1 border_width_top = 1 border_width_right = 1 diff --git a/scripts/captain/captain_skills.gd b/scripts/captain/captain_skills.gd index 245457b..9ed6db9 100644 --- a/scripts/captain/captain_skills.gd +++ b/scripts/captain/captain_skills.gd @@ -10,7 +10,7 @@ const DATA := { "lucky": {"name": "Farciarz", "active": false, "values": [0.05, 0.10, 0.25], "color": "e8c76f"}, "explorer": {"name": "Eksplorator", "active": false, "values": [1, 3, 6], "color": "76d9cc"}, "business_shark": {"name": "Rekin biznesu", "active": false, "values": [0.10, 0.30, 0.60], "color": "efb568"}, - "reactor_overload": {"name": "Przeciążenie reaktora", "active": true, "values": [0.20, 0.50, 1.00], "color": "63d9f5"}, + "reactor_overload": {"name": "Przeciążenie reaktora", "active": true, "values": [0.28, 0.70, 1.40], "color": "63d9f5"}, "tactical_maneuver": {"name": "Manewr taktyczny", "active": true, "values": [0.30, 0.60, 1.00], "color": "b9a0ef"}, "efficient_magazine": {"name": "Oszczędny magazynek", "active": false, "values": [0.10, 0.20, 0.50], "color": "a9d69a"}, "miner": {"name": "Górnik", "active": false, "values": [3, 6, 10], "color": "e5ac76"}, diff --git a/scripts/game/damage_types.gd b/scripts/game/damage_types.gd index af4cb29..5b4a05f 100644 --- a/scripts/game/damage_types.gd +++ b/scripts/game/damage_types.gd @@ -21,7 +21,7 @@ static func enemy_profile(level: int, seed_value: int) -> Dictionary: var rng := RandomNumberGenerator.new() rng.seed = seed_value var weights := Vector3(rng.randf_range(0.1, 1.0), rng.randf_range(0.1, 1.0), rng.randf_range(0.1, 1.0)) - var total := lerpf(2.0, 60.0, pow(float(clampi(level, 1, 1000) - 1) / 999.0, 1.25)) + var total := preload("res://scripts/levels/level_balance.gd").enemy_absorption_total(level) return {"kind": rng.randi_range(0, 4), "absorption": weights * total / (weights.x + weights.y + weights.z)} static func describe(values: Vector3) -> String: diff --git a/scripts/game/enemy_health_bar.gd b/scripts/game/enemy_health_bar.gd index 8cde03d..e81f8bc 100644 --- a/scripts/game/enemy_health_bar.gd +++ b/scripts/game/enemy_health_bar.gd @@ -44,7 +44,7 @@ func get_health_ratio() -> float: return clampf(enemy.hull / maxf(enemy.max_hull, 0.001), 0.0, 1.0) func _draw() -> void: - if not is_instance_valid(enemy) or enemy.hull <= 0.0: + if not is_instance_valid(enemy) or enemy.hull <= 0.0 or not GameState.captain.expedition.alien_skills.get("general", false): return var width := 72.0 if enemy.loot_tier == 2 else (56.0 if enemy.loot_tier == 1 else 44.0) var background := Rect2(-width * 0.5, -3.0, width, 6.0) diff --git a/scripts/game/enemy_ship.gd b/scripts/game/enemy_ship.gd index b5246bf..c18f039 100644 --- a/scripts/game/enemy_ship.gd +++ b/scripts/game/enemy_ship.gd @@ -43,6 +43,7 @@ var _slow_remaining := 0.0 var _combat_target: Node2D var virus_controlled := false var _virus_infection_attempted := false +var _research_player_hit := false var _reward_claimed := false func roll_virus_infection() -> bool: @@ -101,7 +102,7 @@ func _ready() -> void: func apply_level_settings(level: int, tier: int) -> void: loot_tier = tier $Sprite2D.modulate = get_tier_tint() - var power := LEVEL_BALANCE.power_scale(level) + var power := LEVEL_BALANCE.enemy_stat_scale(level) var combat_multiplier := 2.0 if tier == 2 else 1.25 var boss_multiplier := 2.0 if tier == 2 else 1.0 var hull_multiplier := 4.0 if tier == 2 else (2.0 if tier == 1 else 1.0) @@ -114,12 +115,12 @@ func apply_level_settings(level: int, tier: int) -> void: weapon_kind = int(profile["kind"]) absorption = profile["absorption"] weapon_damage = 8.0 * power * damage_bonus * combat_multiplier - approach_speed = 62.0 * (1.0 + 0.0005 * (clampi(level, 1, 1000) - 1)) * boss_multiplier + approach_speed = 62.0 * (1.0 + 0.0005 * (clampi(level, 1, LEVEL_BALANCE.MAX_LEVEL) - 1)) * boss_multiplier approach_acceleration = 85.0 * boss_multiplier turn_speed = 1.8 * boss_multiplier activation_range = 760.0 * boss_multiplier - weapon_range = 680.0 * boss_multiplier - weapon_cooldown = maxf(0.55, 1.5 / (1.0 + 0.001 * (clampi(level, 1, 1000) - 1))) / boss_multiplier + weapon_range = 680.0 * boss_multiplier * (0.5 if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0) + weapon_cooldown = maxf(0.55, 1.5 / (1.0 + 0.001 * (clampi(level, 1, LEVEL_BALANCE.MAX_LEVEL) - 1))) / boss_multiplier if tier == 2: # Ease the first encounter, returning smoothly to standard bosses at level 6. var intro := clampf(float(level - 1) / 5.0, 0.0, 1.0) @@ -130,6 +131,16 @@ func apply_level_settings(level: int, tier: int) -> void: weapon_damage *= lerpf(0.5, 1.0, intro) weapon_cooldown *= lerpf(1.25, 1.0, intro) approach_speed *= lerpf(0.8, 1.0, intro) + if tier == 2: + # Independent multipliers preserve the existing intro and shield/hull ratio changes. + max_hull *= LEVEL_BALANCE.BOSS_HULL_MULTIPLIER + hull = max_hull + max_shields *= LEVEL_BALANCE.BOSS_SHIELD_MULTIPLIER + shields = max_shields + weapon_damage *= LEVEL_BALANCE.BOSS_DAMAGE_MULTIPLIER + if level == 1: + weapon_damage *= LEVEL_BALANCE.FIRST_BOSS_DAMAGE_MULTIPLIER + weapon_cooldown *= LEVEL_BALANCE.FIRST_BOSS_FIRE_INTERVAL_MULTIPLIER $CollisionShape2D.scale = Vector2.ONE * boss_multiplier if is_instance_valid(_shield_visual): _shield_visual.scale = Vector2.ONE * get_visual_size() / 64.0 @@ -152,7 +163,7 @@ func get_visual_size() -> float: return 112.0 if loot_tier == 2 else (68.0 if loot_tier == 1 else 56.0) func regenerate_defenses(delta: float) -> void: - if hull <= 0.0 or is_queued_for_deletion(): + if loot_tier == 2 or hull <= 0.0 or is_queued_for_deletion(): return hull = minf(max_hull, hull + max_hull * 0.01 * delta) shields = minf(max_shields, shields + max_shields * 0.01 * delta) @@ -312,7 +323,7 @@ func _fire_plasma(direction: Vector2) -> void: projectile.collision_mask = shot_mask projectile.missile_homing = false var speed := 430.0 if weapon_kind == ItemDefinition.WeaponKind.GAMMA else (950.0 if weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN else 600.0) - projectile.configure(muzzle, direction, weapon_kind, speed, weapon_damage, weapon_range) + projectile.configure(muzzle, direction, weapon_kind, speed, get_shot_damage(), weapon_range) get_parent().add_child(projectile) WEAPON_AUDIO_SCRIPT.play(get_parent(), global_position, weapon_kind, -4.0) @@ -320,7 +331,9 @@ func take_weapon_hit(amount: float, critical: bool, damage_type: int = DamageTyp if is_queued_for_deletion() or hull <= 0.0: return var before := hull + shields + _research_player_hit = true take_damage(amount, critical, damage_type) + _research_player_hit = false if is_instance_valid(_player): _player.call("restore_shields_from_damage", maxf(0.0, before - hull - shields)) @@ -328,9 +341,16 @@ func take_damage(amount: float, critical: bool = false, damage_type: int = Damag if is_queued_for_deletion() or hull <= 0.0: return var actual := maxf(0.0, amount) * (1.0 if bypass_absorption else 1.0 - absorption[damage_type] / 100.0) - var shield_damage := minf(shields, actual) + var research := preload("res://scripts/planets/alien_research.gd") + var progress: Resource = GameState.captain.expedition + var shield_multiplier := 1.0 + (research.bonus(progress, "shields") if _research_player_hit else 0.0) + var hull_multiplier := 1.0 + (research.bonus(progress, "hull") if _research_player_hit else 0.0) + var shield_damage := minf(shields, actual * shield_multiplier) + var remaining := maxf(0.0, actual - shield_damage / shield_multiplier) shields -= shield_damage - hull = maxf(0.0, hull - actual + shield_damage) + var hull_damage := minf(hull, remaining * hull_multiplier) + hull = maxf(0.0, hull - hull_damage) + actual = shield_damage + hull_damage if is_instance_valid(_shield_visual): _shield_visual.set_shield_values(shields, max_shields) if shield_damage > 0.0: @@ -358,7 +378,7 @@ func _laser_aim_direction(direction: Vector2) -> Vector2: return direction.rotated(randf_range(-0.02, 0.02)) func get_shot_damage() -> float: - return weapon_damage * (LASER_DAMAGE_MULTIPLIER if weapon_kind == ItemDefinition.WeaponKind.LASER else 1.0) + return weapon_damage * (LASER_DAMAGE_MULTIPLIER if weapon_kind == ItemDefinition.WeaponKind.LASER else 1.0) * (1.0 - preload("res://scripts/planets/alien_research.gd").bonus(GameState.captain.expedition, "weapons")) func get_weapon_dps() -> float: var interval := get_fire_interval() diff --git a/scripts/game/flight_hud.gd b/scripts/game/flight_hud.gd index 035dbe8..55611a6 100644 --- a/scripts/game/flight_hud.gd +++ b/scripts/game/flight_hud.gd @@ -33,6 +33,10 @@ var _debug_item_status: Label var _captain_panel: PanelContainer var _cockpit: Control var _captain_skills_ui: CanvasLayer +var _system_badge: PanelContainer +var _system_title: Label +var _system_mode: Label +var _ship_statistics: PanelContainer func _create_navigation() -> void: var navigation := HBoxContainer.new() @@ -85,6 +89,7 @@ func _ready() -> void: $HUDRoot.add_child(_window_manager) _window_manager.connect("interaction_started", player.get_node("WeaponController").call.bind("block_ui_mouse_input")) _create_sidebar() + _create_ship_statistics() _inventory_clip = Control.new() _inventory_clip.name = "InventoryDrawer" _inventory_clip.clip_contents = false @@ -115,8 +120,9 @@ func _create_sidebar() -> void: _captain_panel = $HUDRoot/CaptainPanel _captain_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT) _captain_panel.position = Vector2(12, 12) - _captain_panel.size = Vector2(244, _captain_panel.get_combined_minimum_size().y) + _captain_panel.size = _captain_panel.get_combined_minimum_size() _captain_panel.resized.connect(_layout_debug) + _create_system_badge() var captain_gear := PanelContainer.new() captain_gear.name = "CaptainEquipment" captain_gear.set_script(preload("res://scripts/ui/captain_equipment_panel.gd")) @@ -140,6 +146,14 @@ func _create_sidebar() -> void: preload("res://scripts/ui/hud_button_style.gd").apply(_debug_item_button, Color("a9ef83")) _debug_item_button.pressed.connect(_give_debug_item) _debug_actions.add_child(_debug_item_button) + var resources_button := Button.new() + resources_button.name = "AddResources" + resources_button.text = "Dodaj surowce" + resources_button.tooltip_text = "+100 każdego surowca kosmicznego i planetarnego, +100 próbek i +100 części" + resources_button.custom_minimum_size.y = 36 + preload("res://scripts/ui/hud_button_style.gd").apply(resources_button, Color("79cba8")) + resources_button.pressed.connect(_give_debug_resources) + _debug_actions.add_child(resources_button) var ammunition_button := Button.new() ammunition_button.name = "AddAmmunition" ammunition_button.text = "Dodaj amunicję" @@ -166,7 +180,7 @@ func _create_sidebar() -> void: _sidebar = PanelContainer.new() _sidebar.name = "ShipDrawer" var style := StyleBoxFlat.new() - style.bg_color = Color(0.025, 0.042, 0.064, 1.0) + style.bg_color = Color(0.025, 0.042, 0.064, 0.48) style.border_color = Color("376779") style.set_border_width_all(1) style.set_corner_radius_all(8) @@ -197,10 +211,10 @@ func _create_sidebar() -> void: preload("res://scripts/ui/hud_button_style.gd").apply(inventory_button, Color("b9a0ef")) $HUDRoot.add_child(_sidebar_toggle) _sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT) - _sidebar_toggle.offset_left = -352 + _sidebar_toggle.offset_left = -233 _sidebar_toggle.offset_right = -12 _sidebar_toggle.offset_top = 12 - _sidebar_toggle.offset_bottom = 122 + _sidebar_toggle.offset_bottom = 83.5 _sidebar_toggle.pressed.connect(_toggle_sidebar) _cockpit = Control.new() _cockpit.name = "Cockpit" @@ -280,9 +294,10 @@ func _layout_sidebar() -> void: var panel_scale := minf(EQUIPMENT_UI_SCALE, available_height / content_height) _sidebar.scale = Vector2.ONE * panel_scale _sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), content_height) - _cockpit.scale = Vector2.ONE * 0.85 - _cockpit.size = Vector2(minf(850.0, ($HUDRoot.size.x - 24) / 0.85), 120) - _cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12) + var cockpit_scale := minf(0.85, ($HUDRoot.size.x - 24.0) / 850.0) + _cockpit.scale = Vector2.ONE * cockpit_scale + _cockpit.size = Vector2(850, 144) + _cockpit.position = Vector2(($HUDRoot.size.x - 850.0 * cockpit_scale) * 0.5, $HUDRoot.size.y - 144.0 * cockpit_scale - 12) if _ability_bar != null: var abilities := _ability_bar.get_parent() as Control abilities.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT) @@ -352,6 +367,7 @@ func _update_energy_bank_button() -> void: func _process(_delta: float) -> void: _update_energy_bank_button() + _update_system_badge() _layout_inventory() _update_ability_bar() _layout_passive_panels() @@ -363,7 +379,7 @@ func _process(_delta: float) -> void: _debug_item_button.disabled = inventory.get_cargo_used() >= inventory.get_cargo_capacity() _debug_item_button.tooltip_text = "Magazyn jest pełny — zwolnij miejsce." if _debug_item_button.disabled else "Losuje przedmiot i addony dla poziomu aktualnego układu." var game := get_parent() - debug_info.text = """POZIOM UKŁADU: %d + debug_info.text = """POZIOM UKŁADU: %d / 120 · %s WROGOWIE: %d PRĘDKOŚĆ: %.1f px/s @@ -373,6 +389,7 @@ Tarcze: %.1f pkt/s %s""".replace("\r", "") % [ GameState.system_level, + "HARD" if preload("res://scripts/levels/level_balance.gd").is_hard(GameState.system_level) else "NORMALNY", int(game.call("get_remaining_enemies")), player.velocity.length(), float(player.call("get_energy_regeneration")), @@ -389,6 +406,16 @@ func _toggle_debug() -> void: _update_debug_toggle() _layout_debug() +func _give_debug_resources() -> void: + var captain: Resource = GameState.captain + for material in preload("res://scripts/planets/planet_rewards.gd").MATERIAL_KEYS: + if material == "parts": continue + captain.minerals[material] = int(captain.minerals.get(material, 0)) + 100 + captain.parts += 100 + captain.expedition.analysis_samples += 100 + captain.expedition.emit_changed() + captain.emit_changed() + func _give_debug_ammunition() -> void: var inventory := player.get_node("ShipInventory") as ShipInventory inventory.ammunition += 10 @@ -574,3 +601,48 @@ func _refresh_passive_skills() -> void: _passive_captain_panel.visible = _passive_skills.get_child_count() > 0 _layout_passive_panels.call_deferred() _layout_debug.call_deferred() + +func _create_system_badge() -> void: + var ui := preload("res://scripts/planets/freighter_menu.gd") + _system_badge = PanelContainer.new() + _system_badge.name = "SystemIndicator" + _system_badge.custom_minimum_size.x = 86 + ui.style(_system_badge, 6, 0.30) + _system_badge.mouse_filter = Control.MOUSE_FILTER_IGNORE + $HUDRoot.add_child(_system_badge) + var stack := VBoxContainer.new() + stack.mouse_filter = Control.MOUSE_FILTER_IGNORE + stack.add_theme_constant_override("separation", 0) + _system_badge.add_child(stack) + _system_title = ui.label(stack, "", 13, ui.GOLD) + _system_mode = ui.label(stack, "", 11, ui.MUTED) + _system_title.autowrap_mode = TextServer.AUTOWRAP_OFF + _system_mode.autowrap_mode = TextServer.AUTOWRAP_OFF + _system_mode.add_theme_font_size_override("font_size", 8) + _system_title.mouse_filter = Control.MOUSE_FILTER_IGNORE + _system_mode.mouse_filter = Control.MOUSE_FILTER_IGNORE + _update_system_badge() + +func _update_system_badge() -> void: + if not is_instance_valid(_system_badge): return + _system_badge.position = Vector2(_captain_panel.position.x + _captain_panel.size.x + 10, _captain_panel.position.y) + _system_title.text = "System %d" % GameState.system_level + _system_mode.text = "HARD" if GameState.system_level > 60 else "NORMALNY" + _system_mode.add_theme_color_override("font_color", Color("e88972") if GameState.system_level > 60 else Color("88a7ae")) + +func _create_ship_statistics() -> void: + _ship_statistics = preload("res://scripts/ui/ship_statistics.gd").new() + _ship_statistics.player = player + _ship_statistics.inventory = player.get_node("ShipInventory") + $HUDRoot.add_child(_ship_statistics) + _window_manager.register_window(_ship_statistics, _ship_statistics, _ship_statistics._header) + var contents := _sidebar.get_node("Scroll/Contents/ShipEquipmentPanel/Contents") + var button := Button.new() + button.name = "StatisticsButton" + button.text = "Statystyki" + button.custom_minimum_size.y = 36 + button.tooltip_text = "Parametry statku, uzbrojenie, pancerz i systemy" + preload("res://scripts/ui/hud_button_style.gd").apply(button, Color("83c7e6")) + contents.add_child(button) + contents.move_child(button, inventory_button.get_index() + 1) + button.pressed.connect(_ship_statistics.open) diff --git a/scripts/items/ship_inventory.gd b/scripts/items/ship_inventory.gd index e9c2756..ba82071 100644 --- a/scripts/items/ship_inventory.gd +++ b/scripts/items/ship_inventory.gd @@ -7,15 +7,16 @@ signal ammunition_changed const RECIPES := preload("res://scripts/items/crafting_recipes.gd") const CARGO_SIZE := 20 const CARGO_ROW_SIZE := 5 -const CARGO_ROW_COUNT := CARGO_SIZE / CARGO_ROW_SIZE -var unlocked_cargo_rows := 1 +var unlocked_cargo_slots := CARGO_ROW_SIZE const WEAPON_SLOT_COUNT := 3 const STARTING_MISSILE_AMMUNITION := 2 const MISSILE_BUY_BASE_COST := 30 const MISSILE_DEFINITIONS := [preload("res://resources/items/missile_launcher.tres"), preload("res://resources/items/unguided_missile.tres")] const MODULE_SLOT_COUNT := 5 const EXTENSION_SLOT_COUNT := 5 -const SLOT_UNLOCK_IRON_COST := 10 +const CARGO_SLOT_COST := {"iron": 100, "aluminium": 50} +const WEAPON_UNLOCK_COSTS := [100, 500] +const EXTENSION_UNLOCK_BASE_COST := 40 var unlocked_weapon_slots := 1 var unlocked_extension_slots := 1 const MODULE_CATEGORIES := [ItemDefinition.Category.SHIELD, ItemDefinition.Category.ARMOR, ItemDefinition.Category.ENGINE, ItemDefinition.Category.REACTOR, ItemDefinition.Category.COMPUTER] @@ -49,7 +50,7 @@ func _ready() -> void: if GameState.restart_inventory.is_empty(): _add_starter_items() else: - unlocked_cargo_rows = clampi(int(GameState.restart_inventory.get("unlocked_cargo_rows",1)),1,CARGO_ROW_COUNT) + unlocked_cargo_slots = clampi(int(GameState.restart_inventory.get("unlocked_cargo_slots", int(GameState.restart_inventory.get("unlocked_cargo_rows", 1)) * CARGO_ROW_SIZE)), CARGO_ROW_SIZE, CARGO_SIZE) unlocked_weapon_slots = clampi(int(GameState.restart_inventory.get("unlocked_weapon_slots",1)),1,WEAPON_SLOT_COUNT) unlocked_extension_slots = clampi(int(GameState.restart_inventory.get("unlocked_extension_slots",1)),1,EXTENSION_SLOT_COUNT) cargo.assign(GameState.restart_inventory["cargo"]) @@ -76,7 +77,7 @@ func get_cargo_used() -> int: func preserve_for_restart() -> void: # Copy the slot arrays; resources retain levels and individual modifiers. GameState.restart_inventory = { - "unlocked_cargo_rows": unlocked_cargo_rows, + "unlocked_cargo_slots": unlocked_cargo_slots, "unlocked_weapon_slots": unlocked_weapon_slots, "unlocked_extension_slots": unlocked_extension_slots, "cargo": cargo.duplicate(), @@ -258,18 +259,7 @@ func is_slot_unlocked(kind: String, index: int) -> bool: return true func get_cargo_capacity() -> int: - return unlocked_cargo_rows * CARGO_ROW_SIZE - -func can_unlock_cargo_row(captain: Resource) -> bool: - return bool(ship.get("is_docked")) and unlocked_cargo_rows < CARGO_ROW_COUNT and int(captain.minerals.get("iron",0)) >= SLOT_UNLOCK_IRON_COST - -func unlock_cargo_row(captain: Resource) -> bool: - if not can_unlock_cargo_row(captain): return false - captain.minerals["iron"] = int(captain.minerals.get("iron",0)) - SLOT_UNLOCK_IRON_COST - unlocked_cargo_rows += 1 - captain.emit_changed() - inventory_changed.emit() - return true + return unlocked_cargo_slots func can_use_freighter_storage(captain: Resource) -> bool: return bool(ship.get("is_docked")) and captain.expedition.freighter_rooms.get("expansion_3","") == "module_storage" @@ -300,18 +290,42 @@ func retrieve_from_freighter(index: int, expected: ItemInstance, captain: Resour inventory_changed.emit() return true +func get_slot_unlock_cost(kind: String) -> Dictionary: + match kind: + "cargo": + return CARGO_SLOT_COST.duplicate() if unlocked_cargo_slots < CARGO_SIZE else {} + "weapon": + return {"titanium": WEAPON_UNLOCK_COSTS[unlocked_weapon_slots - 1]} if unlocked_weapon_slots < WEAPON_SLOT_COUNT else {} + "extension": + if unlocked_extension_slots >= EXTENSION_SLOT_COUNT: return {} + var amount := EXTENSION_UNLOCK_BASE_COST * (1 << (unlocked_extension_slots - 1)) + return {"iron": amount, "aluminium": amount, "titanium": amount} + return {} + +func get_slot_unlock_cost_text(kind: String) -> String: + var descriptions := PackedStringArray() + var cost := get_slot_unlock_cost(kind) + for mineral in cost: + descriptions.append("%d %s" % [cost[mineral], RECIPES.NAMES[mineral]]) + return " + ".join(descriptions) + func can_unlock_slot(kind: String, captain: Resource) -> bool: if not bool(ship.get("is_docked")): return false - if kind not in ["weapon","extension"]: return false - var count := unlocked_weapon_slots if kind == "weapon" else unlocked_extension_slots - var limit := WEAPON_SLOT_COUNT if kind == "weapon" else EXTENSION_SLOT_COUNT - return count < limit and int(captain.minerals.get("iron",0)) >= SLOT_UNLOCK_IRON_COST + var cost := get_slot_unlock_cost(kind) + if cost.is_empty(): return false + for mineral in cost: + if int(captain.minerals.get(mineral, 0)) < int(cost[mineral]): return false + return true func unlock_slot(kind: String, captain: Resource) -> bool: - if not can_unlock_slot(kind,captain): return false - captain.minerals["iron"] = int(captain.minerals.get("iron",0)) - SLOT_UNLOCK_IRON_COST - if kind == "weapon": unlocked_weapon_slots += 1 - else: unlocked_extension_slots += 1 + if not can_unlock_slot(kind, captain): return false + var cost := get_slot_unlock_cost(kind) + for mineral in cost: + captain.minerals[mineral] = int(captain.minerals.get(mineral, 0)) - int(cost[mineral]) + match kind: + "cargo": unlocked_cargo_slots += 1 + "weapon": unlocked_weapon_slots += 1 + "extension": unlocked_extension_slots += 1 captain.emit_changed() inventory_changed.emit() return true @@ -521,12 +535,16 @@ func buy_irradiated_ammunition() -> bool: ammunition_changed.emit() return true +func get_weapon_dps(slot_index: int) -> float: + if not is_slot_unlocked("weapon", slot_index): return 0.0 + var item := get_item("weapon", slot_index) + var value := _weapon_dps(item, _comparison_bonuses()) + if item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA: + value *= 1.0 + 0.25 * minf(preload("res://scripts/game/radiation_status.gd").DURATION, item.definition.fire_interval) + return value + func get_total_dps() -> float: var total := 0.0 - var bonuses := _comparison_bonuses() - for item in weapon_slots.slice(0,unlocked_weapon_slots): - var value := _weapon_dps(item, bonuses) - if item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA: - value *= 1.0 + 0.25 * minf(preload("res://scripts/game/radiation_status.gd").DURATION, item.definition.fire_interval) - total += value + for index in range(unlocked_weapon_slots): + total += get_weapon_dps(index) return total diff --git a/scripts/levels/level_balance.gd b/scripts/levels/level_balance.gd index dc5494b..fea09b2 100644 --- a/scripts/levels/level_balance.gd +++ b/scripts/levels/level_balance.gd @@ -1,7 +1,14 @@ extends RefCounted -const MAX_LEVEL := 1000 -const COUNT_POINTS := [Vector2(1, 11), Vector2(10, 11), Vector2(15, 11), Vector2(50, 18), Vector2(100, 23), Vector2(250, 29), Vector2(500, 34), Vector2(1000, 40)] +const NORMAL_MAX_LEVEL := 60 +const MAX_LEVEL := 120 +const HARD_STAT_MULTIPLIER := 2.0 +const BOSS_HULL_MULTIPLIER := 5.0 +const BOSS_SHIELD_MULTIPLIER := 3.0 +const BOSS_DAMAGE_MULTIPLIER := 0.5 +const FIRST_BOSS_DAMAGE_MULTIPLIER := 0.25 +const FIRST_BOSS_FIRE_INTERVAL_MULTIPLIER := 2.0 +const COUNT_POINTS := [Vector2(1, 11), Vector2(10, 11), Vector2(15, 11), Vector2(50, 18), Vector2(100, 23), Vector2(120, 24)] const ELITES_PER_LEVEL := 2 static func enemy_count(level: int) -> int: @@ -11,7 +18,7 @@ static func enemy_count(level: int) -> int: var after: Vector2 = COUNT_POINTS[index] if clamped_level <= after.x: return roundi(lerpf(before.y, after.y, inverse_lerp(before.x, after.x, clamped_level))) - return 40 + return 24 static func enemy_tiers(level: int) -> Array[int]: var count := enemy_count(level) @@ -27,3 +34,15 @@ static func enemy_tiers(level: int) -> Array[int]: static func power_scale(level: int) -> float: return 1.0 + 0.05 * (clampi(level, 1, MAX_LEVEL) - 1) + +static func is_hard(level: int) -> bool: + return level > NORMAL_MAX_LEVEL + +static func enemy_stat_scale(level: int) -> float: + return power_scale(level) * (HARD_STAT_MULTIPLIER if is_hard(level) else 1.0) + +static func enemy_absorption_total(level: int) -> float: + var clamped_level := clampi(level, 1, MAX_LEVEL) + if clamped_level <= NORMAL_MAX_LEVEL: + return lerpf(2.0, 30.0, pow(float(clamped_level - 1) / float(NORMAL_MAX_LEVEL - 1), 1.25)) + return lerpf(30.0, 60.0, float(clamped_level - NORMAL_MAX_LEVEL) / float(MAX_LEVEL - NORMAL_MAX_LEVEL)) diff --git a/scripts/planets/alien_research.gd b/scripts/planets/alien_research.gd new file mode 100644 index 0000000..125c1a7 --- /dev/null +++ b/scripts/planets/alien_research.gd @@ -0,0 +1,44 @@ +extends RefCounted +const ACTIVE_IDS := ["general", "weapons", "hull", "shields"] +const BRANCHES := ["weapons", "hull", "shields"] +const TITLES := {"general":"Ogólna wiedza", "weapons":"Wiedza o broni", "hull":"Wiedza o kadłubie", "shields":"Wiedza o tarczach"} + +static func parent(id: String) -> String: + if id == "general": return "" + return id.split("_")[0] if "_" in id else "general" + +static func cost(id: String) -> int: + var depth := 2 if "_" in id else (0 if id == "general" else 1) + return 10 + depth * (depth + 3) + +static func title(id: String) -> String: + return str(TITLES.get(id, "Pusty slot")) + +static func description(id: String) -> String: + match id: + "general": return "Ujawnia paski HP i tarcz wrogów." + "weapons": return "Broń obcych zadaje o 10% mniej obrażeń." + "hull": return "Twoja broń zadaje o 10% więcej obrażeń kadłubom obcych." + "shields": return "Twoja broń zadaje o 10% więcej obrażeń tarczom obcych." + return "Miejsce na przyszłe badanie." + +static func learned_count(progress: Resource) -> int: + var count := 0 + for id in ACTIVE_IDS: + if progress.alien_skills.get(id, false): count += 1 + return count + +static func bonus(progress: Resource, branch: String) -> float: + var learned: Dictionary = progress.alien_skills + return 0.1 if branch in BRANCHES and learned.get(branch, false) else 0.0 + +static func purchase(progress: Resource, id: String) -> bool: + if id not in ACTIVE_IDS: return false + if progress.alien_skills.get(id, false): return false + var prerequisite := parent(id) + if prerequisite != "" and not progress.alien_skills.get(prerequisite, false): return false + if progress.analysis_samples < cost(id): return false + progress.analysis_samples -= cost(id) + progress.alien_skills[id] = true + progress.emit_changed() + return true diff --git a/scripts/planets/alien_research.gd.uid b/scripts/planets/alien_research.gd.uid new file mode 100644 index 0000000..c20d877 --- /dev/null +++ b/scripts/planets/alien_research.gd.uid @@ -0,0 +1 @@ +uid://drnwmxfrswmeb diff --git a/scripts/planets/alien_research_tree.gd b/scripts/planets/alien_research_tree.gd new file mode 100644 index 0000000..88e3778 --- /dev/null +++ b/scripts/planets/alien_research_tree.gd @@ -0,0 +1,96 @@ +extends Control +const DATA := preload("res://scripts/planets/alien_research.gd") +const MENU := preload("res://scripts/planets/freighter_menu.gd") +const COLORS := [Color("dfb775"), Color("e68c77"), Color("79cba8"), Color("7bc9e6")] +var progress: Resource +var refreshed: Callable +var points: Dictionary = {} + +func _ready() -> void: + custom_minimum_size = Vector2(290, 294) + resized.connect(_build) + _build() + +func _build() -> void: + for child in get_children(): + remove_child(child) + child.queue_free() + points.clear() + var width := maxf(290, size.x) + _add_skill("general", Vector2(width * 0.5, 38), COLORS[0]) + for i in range(3): + var branch: String = DATA.BRANCHES[i] + var x := width * (float(i) + 0.5) / 3.0 + _add_skill(branch, Vector2(x, 137), COLORS[i + 1]) + _add_placeholder(branch + "_a", Vector2(x - 31, 252)) + _add_placeholder(branch + "_b", Vector2(x + 31, 252)) + var caption := MENU.label(self, ["BROŃ", "KADŁUB", "TARCZE"][i], 12, MENU.MUTED) + caption.mouse_filter = Control.MOUSE_FILTER_IGNORE + caption.position = Vector2(x - 55, 177) + caption.size = Vector2(110, 18) + caption.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + queue_redraw() + +func _add_skill(id: String, center: Vector2, color: Color) -> void: + points[id] = center + var learned: bool = progress.alien_skills.get(id, false) + var prerequisite := DATA.parent(id) + var unlocked: bool = prerequisite.is_empty() or progress.alien_skills.get(prerequisite, false) + var button := MENU.button(self, "", _purchase.bind(id), learned) + button.set_script(preload("res://scripts/planets/research_skill_button.gd")) + button.name = id + button.position = center - Vector2(28, 34) + button.size = Vector2(56, 68) + button.disabled = learned or not unlocked or progress.analysis_samples < DATA.cost(id) + var status := "Zbadano" if learned else "Koszt: %d próbek" % DATA.cost(id) + if not unlocked: status += "\nWymaga: " + DATA.title(prerequisite) + elif not learned and progress.analysis_samples < DATA.cost(id): status += "\nZa mało próbek" + button.tooltip_text = DATA.title(id) + "\n" + DATA.description(id) + "\n" + status + var icon := TextureRect.new() + icon.texture = load("res://assets/freighter/research/" + id.split("_")[0] + ".png") + icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS + icon.mouse_filter = Control.MOUSE_FILTER_IGNORE + icon.position = Vector2(4, 2) + icon.size = Vector2(48, 48) + if not unlocked: icon.modulate = Color(0.5, 0.55, 0.55, 0.65) + button.add_child(icon) + var price := MENU.label(button, "✓" if learned else str(DATA.cost(id)), 12, color if unlocked else MENU.MUTED) + price.mouse_filter = Control.MOUSE_FILTER_IGNORE + price.position = Vector2(0, 48) + price.size = Vector2(56, 16) + price.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + +func _add_placeholder(id: String, center: Vector2) -> void: + points[id] = center + var slot := MENU.button(self, "", func(): pass) + slot.name = id + slot.disabled = true + slot.focus_mode = Control.FOCUS_NONE + slot.mouse_default_cursor_shape = Control.CURSOR_ARROW + slot.set_script(preload("res://scripts/planets/research_skill_button.gd")) + slot.position = center - Vector2(28, 34) + slot.size = Vector2(56, 68) + slot.tooltip_text = "Pusty slot\nMiejsce na przyszłe badanie." + var mark := MENU.label(slot, "·", 24, MENU.MUTED) + mark.mouse_filter = Control.MOUSE_FILTER_IGNORE + mark.position = Vector2(0, 16) + mark.size = Vector2(56, 28) + mark.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + +func _purchase(id: String) -> void: + if DATA.purchase(progress, id): refreshed.call() + +func _draw() -> void: + for id in points: + var prerequisite := DATA.parent(id) + if prerequisite.is_empty(): continue + var start: Vector2 = points[prerequisite] + Vector2(0, 62 if "_" in id else 34) + var end: Vector2 = points[id] - Vector2(0, 34) + var active: bool = id in DATA.ACTIVE_IDS and progress.alien_skills.get(prerequisite, false) + var color := Color("79b9a4") if active else Color("3c5158") + var middle := (start.y + end.y) * 0.5 + if "_" in id: middle = end.y - 12 + draw_polyline(PackedVector2Array([start, Vector2(start.x, middle), Vector2(end.x, middle), end]), color, 1.5, true) + diff --git a/scripts/planets/alien_research_tree.gd.uid b/scripts/planets/alien_research_tree.gd.uid new file mode 100644 index 0000000..90e8c26 --- /dev/null +++ b/scripts/planets/alien_research_tree.gd.uid @@ -0,0 +1 @@ +uid://bdlpn4d56mrxw diff --git a/scripts/planets/expedition_controller.gd b/scripts/planets/expedition_controller.gd index a62afe7..fa3005b 100644 --- a/scripts/planets/expedition_controller.gd +++ b/scripts/planets/expedition_controller.gd @@ -38,12 +38,6 @@ func _ready() -> void: sprite.scale = Vector2.ONE * FREIGHTER_SIZE / maxf(sprite.texture.get_width(),sprite.texture.get_height()) _freighter_half_size = Vector2(sprite.texture.get_image().get_used_rect().size)*sprite.scale*0.5 freighter.add_child(sprite) - var label := Label.new() - label.text = "FRACHTOWIEC [L]" - label.position = Vector2(-95,153) - label.add_theme_font_size_override("font_size",15) - label.add_theme_color_override("font_color",UI.CYAN) - freighter.add_child(label) _layer = CanvasLayer.new() _layer.layer = 60 add_child(_layer) diff --git a/scripts/planets/expedition_ui.gd b/scripts/planets/expedition_ui.gd index eca59a2..cf863ff 100644 --- a/scripts/planets/expedition_ui.gd +++ b/scripts/planets/expedition_ui.gd @@ -1,39 +1,42 @@ extends Control ## Shared, compact visual vocabulary for the expedition screens. +const COMPACT := preload("res://scripts/ui/compact_interface.gd") const INK := Color("#08151f") const CYAN := Color("#81dce4") static func panel(parent: Node, minimum := Vector2.ZERO) -> PanelContainer: var node := PanelContainer.new() node.custom_minimum_size = minimum var style := StyleBoxFlat.new() - style.bg_color = Color(0.025, 0.065, 0.095, 0.96) + style.bg_color = Color(0.025, 0.065, 0.095, COMPACT.WINDOW_ALPHA) style.border_color = Color("#345763") style.set_border_width_all(1) - style.set_corner_radius_all(12) - style.content_margin_left = 20 - style.content_margin_right = 20 - style.content_margin_top = 16 - style.content_margin_bottom = 16 + style.set_corner_radius_all(COMPACT.CORNER_RADIUS) + style.content_margin_left = 10 + style.content_margin_right = 10 + style.content_margin_top = 8 + style.content_margin_bottom = 8 node.add_theme_stylebox_override("panel", style) parent.add_child(node) return node static func label(parent: Node, text: String, size := 16, color := Color("#d5e4e8")) -> Label: var node := Label.new() node.text = text - node.add_theme_font_size_override("font_size", size) + node.add_theme_font_size_override("font_size", COMPACT.font_size(size)) node.add_theme_color_override("font_color", color) parent.add_child(node) return node static func button(parent: Node, text: String, action: Callable) -> Button: var node := Button.new() node.text = text - node.custom_minimum_size.y = 40 + node.add_theme_font_size_override("font_size", COMPACT.BODY_SIZE) + node.custom_minimum_size.y = 30 node.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND for state in ["normal", "hover", "pressed", "disabled"]: var style := StyleBoxFlat.new() style.bg_color = Color("#15303e") if state == "normal" else Color("#235465") if state == "disabled": style.bg_color = Color("#101e26") + style.bg_color.a = 0.48 if state == "normal" else 0.64 style.border_color = Color("#426d7d") if state != "hover" else CYAN style.set_border_width_all(1) style.set_corner_radius_all(6) diff --git a/scripts/planets/freighter_deck.gd b/scripts/planets/freighter_deck.gd index cf30082..c62585b 100644 --- a/scripts/planets/freighter_deck.gd +++ b/scripts/planets/freighter_deck.gd @@ -208,7 +208,7 @@ func _draw_tag(section: Dictionary) -> void: var box := _tag_styles.get(section.id) as StyleBoxFlat if box == null: box = StyleBoxFlat.new() - box.bg_color = Color(0.018,0.035,0.043,0.91) + box.bg_color = Color(0.018,0.035,0.043,0.50) box.border_color = Color(color,0.38) box.set_border_width_all(1) box.set_corner_radius_all(4) diff --git a/scripts/planets/freighter_menu.gd b/scripts/planets/freighter_menu.gd index e44e95f..7b92f60 100644 --- a/scripts/planets/freighter_menu.gd +++ b/scripts/planets/freighter_menu.gd @@ -1,19 +1,20 @@ extends RefCounted ## Compact industrial service UI shared by the three operational rooms. +const COMPACT := preload("res://scripts/ui/compact_interface.gd") const TEXT := Color("dce1dc") const MUTED := Color("8faaa7") const GOLD := Color("dfb775") const ORDER := ["workshop","storage","hangar"] -static func style(panel: PanelContainer, inset := 12, opacity := 0.86) -> void: +static func style(panel: PanelContainer, inset := 8, opacity := COMPACT.WINDOW_ALPHA) -> void: var box := StyleBoxFlat.new() - box.bg_color = Color(Color("131e23"),opacity) + box.bg_color = Color(Color("131e23"),minf(opacity, 0.64)) box.border_color = Color("536463") box.set_border_width_all(1) - box.set_corner_radius_all(7) + box.set_corner_radius_all(COMPACT.CORNER_RADIUS) box.set_content_margin_all(inset) box.shadow_color = Color(0,0,0,0.4) - box.shadow_size = 10 + box.shadow_size = 4 panel.add_theme_stylebox_override("panel",box) static func label(parent: Node, value: String, font_size := 13, color := TEXT) -> Label: @@ -21,8 +22,10 @@ static func label(parent: Node, value: String, font_size := 13, color := TEXT) - node.text = value node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART node.add_theme_font_override("font",ThemeDB.fallback_font) - node.add_theme_font_size_override("font_size",maxi(10,font_size-2)) + node.add_theme_font_size_override("font_size",COMPACT.font_size(font_size-2)) node.add_theme_color_override("font_color",color) + node.add_theme_color_override("font_shadow_color",Color(0,0,0,0.75)) + node.add_theme_constant_override("shadow_offset_y",1) parent.add_child(node) return node @@ -30,7 +33,7 @@ static func button(parent: Node, value: String, action: Callable, primary := fal var node := Button.new() node.text = value node.autowrap_mode = TextServer.AUTOWRAP_OFF - node.custom_minimum_size.y = 32 + node.custom_minimum_size.y = 28 node.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND node.add_theme_font_override("font",ThemeDB.fallback_font) node.add_theme_font_size_override("font_size",11) @@ -42,7 +45,7 @@ static func button(parent: Node, value: String, action: Callable, primary := fal if state == "hover": box.bg_color = Color("526b64") if state == "pressed": box.bg_color = Color("354b46") if state == "disabled": box.bg_color = Color("1b272c") - box.bg_color.a = 0.92 + box.bg_color.a = 0.48 if state == "normal" else 0.62 box.border_color = GOLD if primary else Color("4b6569") if state == "focus": box.border_color = GOLD box.set_border_width_all(1) @@ -65,7 +68,7 @@ static func row(parent: Node) -> HBoxContainer: static func card(parent: Node) -> VBoxContainer: var panel := PanelContainer.new() panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL - style(panel,10,0.70) + style(panel,6,COMPACT.CARD_ALPHA) parent.add_child(panel) var stack := VBoxContainer.new() stack.add_theme_constant_override("separation",6) diff --git a/scripts/planets/freighter_screen.gd b/scripts/planets/freighter_screen.gd index 065ff16..fe098a0 100644 --- a/scripts/planets/freighter_screen.gd +++ b/scripts/planets/freighter_screen.gd @@ -108,11 +108,14 @@ func _layout() -> void: if not is_instance_valid(_drawer): return var viewport_size := size var storage: bool = _tab == "storage" or (_tab == "expansion_3" and deck.is_built(_tab)) - var width := minf(700 if storage else (440 if _tab == "hangar" else 490),viewport_size.x-32) - var target_height := 420 if _tab == "hangar" else (520 if _tab == "workshop" else (600 if storage else (300 if _tab == "command" else 260))) + var research: bool = _tab == "expansion_2" and deck.is_built(_tab) + var width := minf(490 if research else (700 if storage else (440 if _tab == "hangar" else 490)),viewport_size.x-32) + var construction: bool = deck.is_buildable(_tab) and not deck.is_built(_tab) + var target_height := 390 if construction else 430 if research else 420 if _tab == "hangar" else (520 if _tab == "workshop" else (600 if storage else (300 if _tab == "command" else 260))) var height := minf(target_height,maxf(240,viewport_size.y-140)) _drawer.position = Vector2(16 if _tab == "hangar" else viewport_size.x-width-16,maxf(90,(viewport_size.y-height)*0.5)) _drawer.size = Vector2(width,height) + MENU.style(_drawer) if is_instance_valid(_storage_columns): _storage_columns.columns = 2 if width >= 640 else 1 func _sync_header() -> void: @@ -193,20 +196,55 @@ func _build_room() -> void: _label("Wybierz pomieszczenie na pokładzie.") return var plan: Dictionary = deck.plan(_tab) + if str(plan.kind) == "alien_research" and deck.is_built(_tab): + _build_alien_research() + return _label("ZBUDOWANO" if deck.is_built(_tab) else "W REMONCIE",21,UI.CYAN if deck.is_built(_tab) else Color("e0b16a")) _label(str(plan.description)) - if str(plan.kind) == "alien_research": - _label("Próbki oczekujące na analizę: %d" % captain.expedition.analysis_samples,16,UI.CYAN) - _label("Próbki z jaskiń są przechowywane po powrocie. Analiza będzie dostępna później.",13) if deck.is_built(_tab): _label("Pomieszczenie jest wyposażone. Jego mechanika zostanie dodana w kolejnym etapie.",14,Color("849da5")) else: - _label("Budowa jest teraz bezpłatna. Wyposażenie pojawi się od razu na pokładzie.",14,Color("849da5")) - MENU.button(_content,"ZBUDUJ · BEZ KOSZTÓW",_construct_room.bind(_tab)) + _build_construction(_content, _tab, "ZBUDUJ SEKCJĘ") MENU.button(_content,"Wróć na pokład",_close_section) +func _can_construct(id: String) -> bool: + if not deck.is_buildable(id) or deck.is_built(id): return false + for mineral in RECIPES.MINERALS: + if int(captain.minerals.get(mineral, 0)) < 100: return false + return true + +func _build_construction(parent: Node, id: String, title: String) -> void: + var costs := MENU.card(parent) + MENU.style(costs.get_parent(), 8, 0.56) + costs.add_theme_constant_override("separation", 3) + var header := MENU.row(costs) + var caption := MENU.label(header, "KOSZT BUDOWY", 12, MENU.GOLD) + caption.size_flags_horizontal = Control.SIZE_EXPAND_FILL + caption.autowrap_mode = TextServer.AUTOWRAP_OFF + MENU.label(header, "POSIADASZ / WYMAGANE", 11, MENU.MUTED).autowrap_mode = TextServer.AUTOWRAP_OFF + for mineral in RECIPES.MINERALS: + var row := MENU.row(costs) + row.name = "Cost" + str(mineral).capitalize() + row.custom_minimum_size.y = 22 + MENU.icon(row, RECIPES.icon(mineral), 18).mouse_filter = Control.MOUSE_FILTER_IGNORE + var resource_name := MENU.label(row, RECIPES.NAMES[mineral], 12) + resource_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL + resource_name.autowrap_mode = TextServer.AUTOWRAP_OFF + var owned := int(captain.minerals.get(mineral, 0)) + var amount := MENU.label(row, "%d / 100" % owned, 12, UI.CYAN if owned >= 100 else Color("ef8e84")) + amount.name = "Amount" + amount.autowrap_mode = TextServer.AUTOWRAP_OFF + amount.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + amount.custom_minimum_size.x = 80 + var build := MENU.button(parent, title, _construct_room.bind(id), true) + build.disabled = not _can_construct(id) + build.tooltip_text = "Budowa wymaga po 100 każdego z pięciu surowców kosmicznych." + func _construct_room(id: String) -> void: - if not deck.is_buildable(id) or deck.is_built(id): return + if not _can_construct(id): return + for mineral in RECIPES.MINERALS: + captain.minerals[mineral] = int(captain.minerals.get(mineral, 0)) - 100 + captain.emit_changed() captain.expedition.freighter_rooms[id] = str(deck.plan(id).kind) captain.expedition.emit_changed() deck.sync_rooms(captain.expedition.freighter_rooms) @@ -280,8 +318,8 @@ func _build_slot_upgrades() -> void: grid.add_theme_constant_override("h_separation",6) _content.add_child(grid) for kind in ["cargo","weapon","extension"]: - var count: int = inventory.unlocked_cargo_rows if kind == "cargo" else (inventory.unlocked_weapon_slots if kind == "weapon" else inventory.unlocked_extension_slots) - var limit: int = inventory.CARGO_ROW_COUNT if kind == "cargo" else (inventory.WEAPON_SLOT_COUNT if kind == "weapon" else inventory.EXTENSION_SLOT_COUNT) + var count: int = inventory.unlocked_cargo_slots if kind == "cargo" else (inventory.unlocked_weapon_slots if kind == "weapon" else inventory.unlocked_extension_slots) + var limit: int = inventory.CARGO_SIZE if kind == "cargo" else (inventory.WEAPON_SLOT_COUNT if kind == "weapon" else inventory.EXTENSION_SLOT_COUNT) var card := MENU.card(grid) MENU.style(card.get_parent(),6,0.70) card.add_theme_constant_override("separation",4) @@ -296,19 +334,27 @@ func _build_slot_upgrades() -> void: MENU.label(title,"%d / %d" % [count,limit],11,MENU.MUTED) var action := MENU.row(card) action.add_theme_constant_override("separation",4) - MENU.icon(action,RECIPES.icon("iron"),14) - var price := MENU.label(action,"10",11,MENU.MUTED) - price.size_flags_horizontal = Control.SIZE_EXPAND_FILL + var prices := VBoxContainer.new() + prices.size_flags_horizontal = Control.SIZE_EXPAND_FILL + prices.add_theme_constant_override("separation", 1) + action.add_child(prices) + var cost: Dictionary = inventory.get_slot_unlock_cost(kind) + for mineral in cost: + var price_row := MENU.row(prices) + price_row.add_theme_constant_override("separation", 3) + price_row.tooltip_text = RECIPES.NAMES[mineral] + MENU.icon(price_row, RECIPES.icon(mineral), 14).mouse_filter = Control.MOUSE_FILTER_IGNORE + MENU.label(price_row, str(cost[mineral]), 11, MENU.MUTED).autowrap_mode = TextServer.AUTOWRAP_OFF var unlock := MENU.button(action,"+1" if count < limit else "✓",_unlock_ship_slot.bind(kind),true) unlock.name = "Unlock"+kind.capitalize() unlock.custom_minimum_size = Vector2(30,24) - unlock.tooltip_text = "Osiągnięto limit." if count >= limit else "Odblokuj %s · koszt 10 żelaza." % ("rząd ładowni (+5 miejsc)" if kind == "cargo" else "kolejny slot") - unlock.disabled = not (inventory.can_unlock_cargo_row(captain) if kind == "cargo" else inventory.can_unlock_slot(kind,captain)) + unlock.size_flags_vertical = Control.SIZE_SHRINK_CENTER + unlock.tooltip_text = "Osiągnięto limit." if count >= limit else "Odblokuj 1 slot · " + inventory.get_slot_unlock_cost_text(kind) + unlock.disabled = not inventory.can_unlock_slot(kind,captain) func _unlock_ship_slot(kind: String) -> void: if is_instance_valid(inventory): - if kind == "cargo": inventory.unlock_cargo_row(captain) - else: inventory.unlock_slot(kind,captain) + inventory.unlock_slot(kind,captain) _refresh() func _build_storage() -> void: @@ -317,7 +363,7 @@ func _build_storage() -> void: _build_resource_overview() var construction := MENU.card(_content) MENU.label(construction,"SKŁAD MODUŁÓW W REMONCIE",15,MENU.GOLD) - MENU.button(construction,"ZBUDUJ SKŁAD · BEZ KOSZTÓW",_construct_room.bind("expansion_3"),true) + _build_construction(construction, "expansion_3", "ZBUDUJ SKŁAD") return if not is_instance_valid(inventory): return _label("MODUŁY / Kliknij ikonę, aby przenieść przedmiot",14,MENU.GOLD) @@ -524,3 +570,20 @@ func _craft(kind: String) -> void: func _equip(kind: String, uid: int) -> void: GEAR.equip(captain,kind,uid) _refresh() + +func _build_alien_research() -> void: + var progress: Resource = captain.expedition + var row := MENU.row(_content) + var balance := MENU.label(row, "PRÓBKI / %d" % progress.analysis_samples, 15, MENU.GOLD) + balance.size_flags_horizontal = Control.SIZE_EXPAND_FILL + MENU.label(row, "%d / 4 ZBADANO" % preload("res://scripts/planets/alien_research.gd").learned_count(progress), 12, MENU.MUTED).custom_minimum_size.x = 110 + var tree := preload("res://scripts/planets/alien_research_tree.gd").new() + tree.progress = progress + tree.refreshed = _research_completed + tree.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _content.add_child(tree) + +func _research_completed() -> void: + _audio.service_completed() + captain.emit_changed() + _refresh() diff --git a/scripts/planets/freighter_storage_slot.gd b/scripts/planets/freighter_storage_slot.gd index 2e200d7..3380490 100644 --- a/scripts/planets/freighter_storage_slot.gd +++ b/scripts/planets/freighter_storage_slot.gd @@ -12,7 +12,7 @@ func _ready() -> void: for state in ["normal","hover","pressed","disabled","focus"]: var box := StyleBoxFlat.new() box.bg_color = Color("13222a") if not locked else Color("11191d") - box.bg_color.a = 0.85 + box.bg_color.a = 0.36 box.border_color = accent if state != "hover" else Color("e7c38a") box.set_border_width_all(1) box.set_corner_radius_all(4) @@ -46,4 +46,4 @@ func _ready() -> void: else: disabled = true text = "×" if locked else "·" - tooltip_text = "Odblokuj kolejne rzędy ładowni w Hangarze." if locked else "Wolny slot" + tooltip_text = "Odblokuj 1 slot ładowni w hangarze: 100 żelaza + 50 aluminium." if locked else "Wolny slot" diff --git a/scripts/planets/planet_progress.gd b/scripts/planets/planet_progress.gd index 2ab119d..cf90f04 100644 --- a/scripts/planets/planet_progress.gd +++ b/scripts/planets/planet_progress.gd @@ -7,6 +7,7 @@ const PROFILES := preload("res://scripts/planets/planet_profiles.gd") @export var scans: Dictionary = {} @export var delivered_modules: Array[Resource] = [] @export var research_records: Dictionary = {} +@export var alien_skills: Dictionary = {} @export var freighter_rooms: Dictionary = {} @export var freighter_storage: Array[Resource] = [] @export var delivered_missiles := 0 diff --git a/scripts/planets/poi_presentation.gd b/scripts/planets/poi_presentation.gd index a71a636..797e07e 100644 --- a/scripts/planets/poi_presentation.gd +++ b/scripts/planets/poi_presentation.gd @@ -14,11 +14,11 @@ const STORIES := { static func panel_style(panel: PanelContainer) -> void: var style := StyleBoxFlat.new() - style.bg_color = Color("22271f") + style.bg_color = Color("22271f7a") style.border_color = Color("756d50") style.set_border_width_all(1) style.set_corner_radius_all(8) - style.set_content_margin_all(14) + style.set_content_margin_all(9) style.shadow_color = Color(0,0,0,0.45) style.shadow_size = 14 panel.add_theme_stylebox_override("panel",style) @@ -27,7 +27,7 @@ static func text(parent: Node, content: String, font_size := 14, color := INK) - var label := Label.new() label.text = content label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - label.add_theme_font_size_override("font_size",maxi(11,font_size-(3 if font_size >= 20 else 2))) + label.add_theme_font_size_override("font_size",preload("res://scripts/ui/compact_interface.gd").font_size(font_size-2)) label.add_theme_font_override("font",ThemeDB.fallback_font) label.add_theme_color_override("font_color",color) parent.add_child(label) @@ -37,7 +37,7 @@ static func button(parent: Node, content: String, action: Callable, primary := f var node := Button.new() node.text = content node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - node.custom_minimum_size.y = 36 + node.custom_minimum_size.y = 30 node.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND node.add_theme_font_size_override("font_size",12) node.add_theme_font_override("font",ThemeDB.fallback_font) @@ -48,6 +48,7 @@ static func button(parent: Node, content: String, action: Callable, primary := f if state == "hover": style.bg_color = Color("626b46") if state == "pressed": style.bg_color = Color("3c442c") if state == "disabled": style.bg_color = Color("292c25") + style.bg_color.a = 0.50 if state == "normal" else 0.66 style.border_color = GOLD if primary else Color("687054") style.set_border_width_all(1) style.set_corner_radius_all(4) diff --git a/scripts/planets/research_skill_button.gd b/scripts/planets/research_skill_button.gd new file mode 100644 index 0000000..2341200 --- /dev/null +++ b/scripts/planets/research_skill_button.gd @@ -0,0 +1,16 @@ +extends Button +const MENU := preload("res://scripts/planets/freighter_menu.gd") + +func _make_custom_tooltip(for_text: String) -> Object: + var panel := PanelContainer.new() + MENU.style(panel, 10, 0.98) + panel.custom_minimum_size.x = 260 + var stack := VBoxContainer.new() + stack.add_theme_constant_override("separation", 5) + panel.add_child(stack) + var lines := for_text.split("\n") + for i in range(lines.size()): + var label := MENU.label(stack, lines[i], 14 if i == 0 else 13, MENU.GOLD if i == 0 else MENU.TEXT) + label.custom_minimum_size.x = 240 + label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + return panel diff --git a/scripts/planets/research_skill_button.gd.uid b/scripts/planets/research_skill_button.gd.uid new file mode 100644 index 0000000..2bb039e --- /dev/null +++ b/scripts/planets/research_skill_button.gd.uid @@ -0,0 +1 @@ +uid://cbo78ihtxcfcm diff --git a/scripts/planets/surface_clouds.gd b/scripts/planets/surface_clouds.gd index 33ac8a4..920122b 100644 --- a/scripts/planets/surface_clouds.gd +++ b/scripts/planets/surface_clouds.gd @@ -1,11 +1,16 @@ extends Node2D -## Terrain scrolls at 1x; this elevated mist moves at 1.22x and 1.34x. +## Two elevated cloud decks, with weather-driven coverage, color and moving shadows. const TEXTURE := preload("res://assets/planets/cloud_mist.png") var seed_value := 0 var _banks: Array[Dictionary] = [] var _time := 0.0 var clouds: Node2D var shadows: Node2D +var coverage := 0.8 +var darkness := 0.0 +var weather_wind := Vector2(18,6) +var _coverage := 0.8 +var _darkness := 0.0 func _ready() -> void: texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS @@ -21,32 +26,43 @@ func _ready() -> void: rng.seed = seed_value ^ 0x434c4f55 var mist_material := ShaderMaterial.new() mist_material.shader = preload("res://resources/effects/cloud_mist.gdshader") - for y in range(-3,4): - for x in range(-3,4): - var mist := Sprite2D.new() - mist.texture = TEXTURE - mist.material = mist_material - mist.scale = Vector2.ONE*rng.randf_range(1050,1550)/TEXTURE.get_width() - mist.rotation = rng.randf_range(-PI,PI) - mist.modulate = Color(0.9,0.95,1.0,rng.randf_range(0.24,0.34)) - clouds.add_child(mist) - var shadow := Sprite2D.new() - shadow.texture = TEXTURE - shadow.material = mist_material - shadow.scale = mist.scale - shadow.rotation = mist.rotation - shadow.modulate = Color(0.02,0.04,0.06,0.055) - shadows.add_child(shadow) - _banks.append({"mist":mist,"shadow":shadow,"origin":Vector2(x*800,y*800)+Vector2(rng.randf_range(-240,240),rng.randf_range(-240,240)),"parallax":1.22 if (x+y)%2 == 0 else 1.34,"speed":rng.randf_range(5,10)}) + for layer in range(2): + var radius := 3 if layer == 0 else 2 + for y in range(-radius,radius+1): + for x in range(-radius,radius+1): + var mist := Sprite2D.new() + mist.texture = TEXTURE + mist.material = mist_material + mist.scale = Vector2.ONE*rng.randf_range(1250,1750)/TEXTURE.get_width() * (1.25 if layer == 1 else 1.0) + mist.rotation = rng.randf_range(-PI,PI) + clouds.add_child(mist) + var shadow := Sprite2D.new() + shadow.texture = TEXTURE + shadow.material = mist_material + shadow.scale = mist.scale + shadow.rotation = mist.rotation + shadows.add_child(shadow) + _banks.append({"mist":mist,"shadow":shadow,"origin":Vector2(x*750,y*750)+Vector2(rng.randf_range(-200,200),rng.randf_range(-200,200)),"parallax":1.22 if layer == 0 else 1.38,"speed":rng.randf_range(0.25,0.55),"layer":layer,"alpha":rng.randf_range(0.21,0.30)}) _process(0) +func set_weather(cloud_cover: float, dark: float, wind: Vector2) -> void: + coverage = clampf(cloud_cover,0.0,1.8) + darkness = clampf(dark,0.0,1.0) + weather_wind = wind + func _process(delta: float) -> void: _time += delta + _coverage = move_toward(_coverage,coverage,delta*0.22) + _darkness = move_toward(_darkness,darkness,delta*0.12) var camera := get_viewport().get_camera_2d() var center := camera.get_screen_center_position() if camera != null else Vector2.ZERO for bank in _banks: - var drift := Vector2(float(bank.speed)*_time,float(bank.speed)*_time*0.3) - var drifting: Vector2 = bank.origin+drift - var location: Vector2 = Vector2(wrapf(drifting.x,-2800,2800),wrapf(drifting.y,-2800,2800))+center*(1.0-float(bank.parallax)) + bank.origin += weather_wind*float(bank.speed)*delta + var location := Vector2(wrapf(bank.origin.x,-2800,2800),wrapf(bank.origin.y,-2800,2800))+center*(1.0-float(bank.parallax)) bank.mist.position = location - bank.shadow.position = location+Vector2(35,45) + bank.shadow.position = location+Vector2(45,60) + var color := Color("d6e0e8").lerp(Color("060b14"),_darkness*0.98) + var amount := _coverage if int(bank.layer) == 0 else _coverage*smoothstep(0.20,0.85,_darkness)*0.55 + color.a = float(bank.alpha)*amount + bank.mist.modulate = color + bank.shadow.modulate = Color(0.02,0.035,0.06,amount*(0.025+_darkness*0.055)) diff --git a/scripts/planets/surface_generator.gd b/scripts/planets/surface_generator.gd index fa79959..a70a749 100644 --- a/scripts/planets/surface_generator.gd +++ b/scripts/planets/surface_generator.gd @@ -4,6 +4,8 @@ const GRID := 96 const CELL := 40.0 const WORLD_SIZE := GRID * CELL const EXTRA_STRUCTURE_CHANCE := 0.25 +const MIN_NATURAL_POIS := 5 +const MAX_NATURAL_POIS := 10 static func generate(seed_value: int, profile: Dictionary) -> Dictionary: var rng := RandomNumberGenerator.new() @@ -51,6 +53,11 @@ static func generate(seed_value: int, profile: Dictionary) -> Dictionary: var pois: Array[Dictionary] = [] var kinds: Array[String] = ["warehouse","ruins","deposit","deposit","village","cave"] if rng.randf() < EXTRA_STRUCTURE_CHANCE: kinds.append("ruins") + # Keep structures unchanged and guarantee at least two caves and two deposits. + kinds.append("cave") + var natural_count := rng.randi_range(MIN_NATURAL_POIS, MAX_NATURAL_POIS) + for extra in range(natural_count - 4): + kinds.append("cave" if rng.randf() < 0.5 else "deposit") for index in kinds.size(): var kind: String = kinds[index] var chosen := Vector2.ZERO diff --git a/scripts/planets/surface_scenery.gd b/scripts/planets/surface_scenery.gd index 6639434..5a993ca 100644 --- a/scripts/planets/surface_scenery.gd +++ b/scripts/planets/surface_scenery.gd @@ -19,7 +19,7 @@ static func generate(data: Dictionary, rng: RandomNumberGenerator) -> void: var kinds: Array = preload("res://scripts/planets/surface_events.gd").KINDS data.events.append({"kind":kinds[event_rng.randi_range(0,kinds.size()-1)],"position":position,"seed":event_rng.randi(),"complete":false,"discovered":false}) data.trees = data.trees.filter(func(prop): return prop.position.distance_to(position) > 90+float(prop.size)*0.3) - data.mountains = data.mountains.filter(func(prop): return prop.position.distance_to(position) > 90+float(prop.size)*0.7) + data.mountains = data.mountains.filter(func(prop): return bool(prop.get("cave_anchor",false)) or prop.position.distance_to(position) > 90+float(prop.size)*0.7) data.rocks = data.rocks.filter(func(prop): return prop.position.distance_to(position) > 80) var clearings: Array = data.structures.duplicate() for clearing in clearings: @@ -73,6 +73,9 @@ static func find_event_site(data: Dictionary, rng: RandomNumberGenerator) -> Vec var clearance := point.length()-310 for poi in data.pois: clearance = minf(clearance,point.distance_to(poi.position)-210) + for mountain in data.mountains: + if mountain.get("cave_anchor",false): + clearance = minf(clearance,point.distance_to(mountain.position)-float(mountain.size)*0.7-90) for structure in data.structures: clearance = minf(clearance,point.distance_to(structure.position)-float(structure.size)*0.65-120) if clearance > best_clearance: diff --git a/scripts/planets/surface_screen.gd b/scripts/planets/surface_screen.gd index 3181e5d..e8e0f29 100644 --- a/scripts/planets/surface_screen.gd +++ b/scripts/planets/surface_screen.gd @@ -285,7 +285,7 @@ func _destroy_lander() -> void: func _update_hud() -> void: _hp.value = progress.lander_hp if not _ending: - _status.text = "Lądownik %d / 100 HP · Energia %d%%" % [ceili(progress.lander_hp),roundi(_motion.energy)] + _status.text = "Lądownik %d / 100 HP · Energia %d%%" % [ceili(progress.lander_hp),roundi(_motion.energy)] + ("\nPogoda: " + weather.display_name() if is_instance_valid(weather) else "") _threat.text = "Ryzyko %.1f%% / 300%% · Śr. POI %.1f%%" % [PROFILES.global_threat(progress.active_profile,captain),PROFILES.average_success_chance(progress.active_profile,captain)*100.0] var loot_data: Dictionary = progress.cargo.duplicate() if progress.cargo_parts > 0: loot_data.parts = progress.cargo_parts diff --git a/scripts/planets/surface_telemetry.gd b/scripts/planets/surface_telemetry.gd index 980e016..751d5d4 100644 --- a/scripts/planets/surface_telemetry.gd +++ b/scripts/planets/surface_telemetry.gd @@ -15,7 +15,7 @@ func text(parent: Node, value: String, font_size := 11, color := INK) -> Label: label.text = value label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART label.add_theme_font_override("font",ThemeDB.fallback_font) - label.add_theme_font_size_override("font_size",font_size) + label.add_theme_font_size_override("font_size",clampi(font_size,10,13)) label.add_theme_color_override("font_color",color) parent.add_child(label) return label @@ -27,14 +27,14 @@ func _ready() -> void: size.x = 350 mouse_filter = Control.MOUSE_FILTER_IGNORE var frame := StyleBoxFlat.new() - frame.bg_color = Color(0.10,0.13,0.10,0.95) + frame.bg_color = Color(0.10,0.13,0.10,0.48) frame.border_color = Color("8b805b") frame.border_width_top = 2 frame.border_width_bottom = 1 frame.border_width_left = 1 frame.border_width_right = 1 frame.set_corner_radius_all(8) - frame.set_content_margin_all(12) + frame.set_content_margin_all(8) frame.shadow_color = Color(0,0,0,0.4) frame.shadow_size = 10 add_theme_stylebox_override("panel",frame) diff --git a/scripts/planets/surface_weather.gd b/scripts/planets/surface_weather.gd index 4b8e78b..09d59a8 100644 --- a/scripts/planets/surface_weather.gd +++ b/scripts/planets/surface_weather.gd @@ -1,6 +1,7 @@ extends Node2D ## World-space weather: bounded particle pool, slow transitions, no screen-space noise. -const LIMIT := 190 +const LIMIT := 360 +const CONDITIONS := preload("res://scripts/planets/surface_weather_conditions.gd") var source: Control var intensity := 0.15 var target_intensity := 0.2 @@ -16,6 +17,10 @@ var _particles: Array[Dictionary] = [] var _fog: Array[Sprite2D] = [] var _biome := 0 var _bolt := PackedVector2Array() +var condition := "clear" +var _darkness := 0.0 +var _clouds: Node2D +var _fog_strength := 0.1 func _ready() -> void: name = "SurfaceWeather" @@ -23,15 +28,15 @@ func _ready() -> void: texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS _rng.seed = source.progress.visit_seed ^ 0x57454154 _biome = int(source.world.data.landscape.index) - mode = ["rain","leaves","rain","wind","dust","snow"][_biome] - target_intensity = 0.38 if _biome in [2,5] else 0.18 + _clouds = get_parent().get_node_or_null("SurfaceAtmosphere") + set_condition(CONDITIONS.pick(_biome,_rng), true) var material := ShaderMaterial.new() material.shader = preload("res://resources/effects/cloud_mist.gdshader") - for index in 12: + for index in 20: var fog := Sprite2D.new() fog.texture = preload("res://assets/planets/cloud_mist.png") fog.material = material - fog.position = Vector2(index%4*1100-1650,index/4*1100-1100) + fog.position = Vector2(index%5*950-1900,index/5*950-1425) fog.rotation = _rng.randf_range(-PI,PI) fog.scale = Vector2.ONE*_rng.randf_range(650,1100)/fog.texture.get_width() fog.z_as_relative = false @@ -51,11 +56,14 @@ func _process(delta: float) -> void: _time += delta _transition -= delta if _transition <= 0: - _transition = _rng.randf_range(38,85) - target_intensity = _rng.randf_range(0.12,0.85) if _biome in [2,4,5] else _rng.randf_range(0.0,0.58) - intensity = move_toward(intensity,target_intensity,delta*0.018) + set_condition(CONDITIONS.pick(_biome,_rng)) + intensity = move_toward(intensity,target_intensity,delta*0.028) var gust := 0.75+0.25*sin(_time*0.19)+0.12*sin(_time*0.57) - wind = Vector2(22,7).rotated(sin(_time*0.045)*0.25)*(0.7+intensity*1.4)*gust + var preset: Dictionary = CONDITIONS.DATA[condition] + _darkness = move_toward(_darkness,float(preset.darkness),delta*0.10) + _fog_strength = move_toward(_fog_strength,float(preset.fog),delta*0.08) + wind = Vector2(22,7).rotated(sin(_time*0.045)*0.25)*(0.7+intensity*1.4)*gust*float(preset.wind) + if is_instance_valid(_clouds): _clouds.set_weather(float(preset.clouds),_darkness,wind) if is_instance_valid(source.world.tree_canopy): source.world.tree_canopy.wind_material.set_shader_parameter("wind_direction",wind.normalized()) source.world.tree_canopy.wind_material.set_shader_parameter("wind_strength",0.5+intensity*1.4) @@ -66,10 +74,13 @@ func _process(delta: float) -> void: fog.position.y = wrapf(fog.position.y,-2100,2100) var h := terrain_height(fog.position) var valley := 1.0-smoothstep(0.42,0.65,h) - fog.modulate.a = (0.035+intensity*0.14)*valley*(1.0 if _biome in [0,1,2,5] else 0.3) + var fog_color := Color(0.79,0.84,0.79).lerp(Color(0.20,0.26,0.32),_darkness*0.65) + fog_color.a = (0.02+_fog_strength*0.24)*valley*(1.0 if _biome in [0,1,2,5] else 0.3) + fog.modulate = fog_color if _biome == 4: for fog in _fog: fog.modulate = Color(0.76,0.62,0.39,fog.modulate.a+intensity*0.04) - _emission += delta*([13,12,34,8,24,34][_biome])*intensity + var emission_rate := 170.0 if mode == "rain" else (85.0 if mode in ["snow","dust"] else 16.0) + _emission += delta*emission_rate*intensity while _emission >= 1: _emission -= 1 if _particles.size() < LIMIT: _spawn() @@ -81,13 +92,10 @@ func _process(delta: float) -> void: p.position += (p.velocity+wind)*delta if p.age > p.life or absf(p.position.x-center.x) > extent.x*1.3 or absf(p.position.y-center.y) > extent.y*1.3: _particles.remove_at(index) - _flash = move_toward(_flash,0,delta*0.8) + _flash = move_toward(_flash,0,delta*0.42) _storm_timer -= delta - if mode == "rain" and intensity > 0.66 and _storm_timer <= 0: - _storm_timer = _rng.randf_range(28,65) - _flash = 0.045 - var point := center+Vector2(_rng.randf_range(-extent.x*0.8,extent.x*0.8),-extent.y*0.7) - _bolt = PackedVector2Array([point,point+Vector2(15,30),point+Vector2(4,45),point+Vector2(31,80)]) + if condition == "storm" and intensity > 0.65 and _storm_timer <= 0: + trigger_lightning() queue_redraw() func terrain_height(point: Vector2) -> float: @@ -98,18 +106,21 @@ func terrain_height(point: Vector2) -> float: func _spawn() -> void: var extent := _extent() var point := _center()+Vector2(_rng.randf_range(-extent.x,extent.x),_rng.randf_range(-extent.y,extent.y)) - var velocity := Vector2(-25,250) if mode == "rain" else Vector2(_rng.randf_range(-8,8),_rng.randf_range(7,22)) - _particles.append({"position":point,"velocity":velocity,"age":0.0,"life":_rng.randf_range(3,6),"size":_rng.randf_range(1.1,2.8),"phase":_rng.randf_range(0,TAU)}) + var velocity := Vector2(-70,460) if mode == "rain" else Vector2(_rng.randf_range(-8,8),_rng.randf_range(7,22)) + _particles.append({"position":point,"velocity":velocity,"age":0.0,"life":_rng.randf_range(0.8,1.6) if mode == "rain" else _rng.randf_range(3,6),"kind":mode,"size":_rng.randf_range(1.1,2.8),"phase":_rng.randf_range(0,TAU)}) func _draw() -> void: + var tint := Color(0.05,0.08,0.14,_darkness*0.12) + if condition == "dust_storm": tint = Color(0.46,0.30,0.12,intensity*0.10) + draw_rect(Rect2(_center()-_extent(),_extent()*2),tint) for p in _particles: var alpha := sin(clampf(p.age/p.life,0,1)*PI) var point: Vector2 = p.position+Vector2(sin(_time*1.6+p.phase)*3,0) - match mode: + match str(p.get("kind",mode)): "rain": - draw_line(point,point+Vector2(-2,12),Color(0.73,0.83,0.86,alpha*0.26),0.8,true) + draw_line(point,point+Vector2(-4,18),Color(0.73,0.83,0.90,alpha*0.48),0.9,true) if terrain_height(point) < 0.32: draw_arc(point+Vector2(-2,12),p.size*1.5,0,TAU,12,Color(0.73,0.83,0.86,alpha*0.10),0.7,true) - "snow": draw_circle(point,p.size,Color(0.91,0.96,0.97,alpha*0.55),true,-1,true) + "snow": draw_circle(point,p.size,Color(0.91,0.96,0.97,alpha*0.65),true,-1,true) "leaves": draw_set_transform(point,sin(_time+p.phase),Vector2(1,0.45)) draw_circle(Vector2.ZERO,p.size,Color(0.61,0.43,0.19,alpha*0.55),true,-1,true) @@ -124,7 +135,36 @@ func _draw() -> void: draw_colored_polygon(PackedVector2Array([start,start+Vector2(50,0),start+Vector2(380,extent.y*2),start+Vector2(210,extent.y*2)]),Color(0.95,0.87,0.62,0.012*(1.0-intensity))) if _flash > 0: draw_rect(Rect2(center-extent,extent*2),Color(0.78,0.84,1.0,_flash)) - draw_polyline(_bolt,Color(0.83,0.90,1.0,_flash*6),1.2,true) + draw_polyline(_bolt,Color(0.83,0.90,1.0,minf(_flash*7,0.85)),2.0,true) func _draw_reset() -> void: draw_set_transform(Vector2.ZERO) + +func set_condition(next: String, immediate := false) -> bool: + if not CONDITIONS.DATA.has(next): return false + condition = next + var preset: Dictionary = CONDITIONS.DATA[condition] + mode = str(preset.mode) + if mode == "wind": mode = "leaves" if _biome == 1 else ("dust" if _biome == 4 else "wind") + target_intensity = float(preset.intensity) + _transition = _rng.randf_range(45,95) + _storm_timer = _rng.randf_range(5,14) + if immediate: + intensity = target_intensity + _darkness = float(preset.darkness) + _fog_strength = float(preset.fog) + if is_instance_valid(_clouds): _clouds.set_weather(float(preset.clouds),float(preset.darkness),wind) + return true + +func display_name() -> String: + return str(CONDITIONS.DATA[condition].name) + +func trigger_lightning() -> void: + _storm_timer = _rng.randf_range(7,18) + _flash = 0.10 + var center := _center() + var extent := _extent() + var point := center+Vector2(_rng.randf_range(-extent.x*0.65,extent.x*0.65),-extent.y*0.85) + _bolt = PackedVector2Array([point]) + for step in range(1,9): + _bolt.append(point+Vector2(_rng.randf_range(-35,35)+step*8,step*30)) diff --git a/scripts/planets/surface_weather_conditions.gd b/scripts/planets/surface_weather_conditions.gd new file mode 100644 index 0000000..150b1b2 --- /dev/null +++ b/scripts/planets/surface_weather_conditions.gd @@ -0,0 +1,23 @@ +extends RefCounted +const DATA := { + "clear":{"name":"Przejaśnienia","mode":"wind","intensity":0.10,"clouds":0.30,"darkness":0.0,"wind":0.7,"fog":0.1}, + "cloudy":{"name":"Chmury i wiatr","mode":"wind","intensity":0.30,"clouds":0.80,"darkness":0.15,"wind":1.0,"fog":0.2}, + "overcast":{"name":"Pełne zachmurzenie","mode":"wind","intensity":0.45,"clouds":1.20,"darkness":0.40,"wind":1.1,"fog":0.4}, + "rain":{"name":"Ulewa","mode":"rain","intensity":0.72,"clouds":1.30,"darkness":0.48,"wind":1.25,"fog":0.5}, + "storm":{"name":"Burza z piorunami","mode":"rain","intensity":0.95,"clouds":1.65,"darkness":0.92,"wind":2.0,"fog":0.25}, + "fog":{"name":"Gęsta mgła","mode":"wind","intensity":0.35,"clouds":0.70,"darkness":0.20,"wind":0.45,"fog":1.0}, + "dust_storm":{"name":"Burza pyłowa","mode":"dust","intensity":0.90,"clouds":1.25,"darkness":0.55,"wind":2.4,"fog":0.85}, + "snow":{"name":"Opady śniegu","mode":"snow","intensity":0.60,"clouds":1.0,"darkness":0.30,"wind":1.0,"fog":0.45}, + "blizzard":{"name":"Zamieć śnieżna","mode":"snow","intensity":0.95,"clouds":1.45,"darkness":0.65,"wind":2.4,"fog":0.8} +} +const CLIMATES := [ + ["clear","cloudy","overcast","rain","storm","fog"], + ["clear","cloudy","overcast","rain","storm","fog"], + ["cloudy","overcast","rain","rain","storm","storm","fog"], + ["clear","cloudy","overcast","rain","storm","fog"], + ["clear","clear","cloudy","dust_storm","dust_storm"], + ["clear","cloudy","overcast","snow","blizzard","fog"] +] +static func pick(biome: int, rng: RandomNumberGenerator) -> String: + var choices: Array = CLIMATES[clampi(biome,0,5)] + return str(choices[rng.randi_range(0, choices.size()-1)]) diff --git a/scripts/planets/surface_weather_conditions.gd.uid b/scripts/planets/surface_weather_conditions.gd.uid new file mode 100644 index 0000000..3d24fdb --- /dev/null +++ b/scripts/planets/surface_weather_conditions.gd.uid @@ -0,0 +1 @@ +uid://dalmata6707jb diff --git a/scripts/ui/captain_panel.gd b/scripts/ui/captain_panel.gd index 778a3db..a1c9d71 100644 --- a/scripts/ui/captain_panel.gd +++ b/scripts/ui/captain_panel.gd @@ -1,6 +1,8 @@ extends PanelContainer signal equipment_requested +const PANEL_SCALE := 1.3 + @onready var player: CharacterBody2D = get_node("../../../PlayerShip") @onready var level_label: Label = $Contents/Header/Level @onready var xp_label: Label = $Contents/XPLabel @@ -9,24 +11,26 @@ signal equipment_requested var _captain: CaptainProgress var _level_up_button: Button +var _frame: Texture2D func _ready() -> void: - _build_portrait() _captain = GameState.captain _captain.normalize_skill_ranks() + _build_portrait() _level_up_button = Button.new() _level_up_button.name = "LevelUpButton" _level_up_button.text = "Nowy poziom" - _level_up_button.custom_minimum_size.y = 32 _level_up_button.focus_mode = Control.FOCUS_NONE preload("res://scripts/ui/hud_button_style.gd").apply(_level_up_button, Color("efb568")) + _level_up_button.add_theme_font_size_override("font_size", 10) $Contents.add_child(_level_up_button) + _place(_level_up_button, Rect2(90, 17, 72, 15)) _level_up_button.pressed.connect(func() -> void: get_node("../../CaptainSkills").call("open_management") ) _captain.changed.connect(_refresh) player.get_node("ShipInventory").connect("inventory_changed", _refresh) - for label in [level_label, xp_label, credits_label]: + for label in [level_label, xp_label, credits_label, $Contents/Header/Title]: label.add_theme_color_override("font_shadow_color", Color("030811")) label.add_theme_constant_override("shadow_offset_x", 1) label.add_theme_constant_override("shadow_offset_y", 1) @@ -35,6 +39,11 @@ func _ready() -> void: tooltip_text = "Kliknij, aby otworzyć ekwipunek kapitana" _pass_clicks($Contents) +func _place(control: Control, rect: Rect2) -> void: + control.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT) + control.position = rect.position * PANEL_SCALE + control.size = rect.size * PANEL_SCALE + func _pass_clicks(node: Node) -> void: for child in node.get_children(): if child is BaseButton: continue @@ -53,53 +62,68 @@ func _refresh() -> void: xp_bar.max_value = _captain.get_xp_required() xp_bar.value = _captain.experience credits_label.text = "Kredyty: %d" % _captain.credits - var available := _captain.learning_points > 0 - if _level_up_button.visible != available: - _level_up_button.visible = available - reset_size.call_deferred() + _level_up_button.visible = _captain.learning_points > 0 + $Contents/Header/Title.visible = not _level_up_button.visible _level_up_button.tooltip_text = "Wybierz umiejętność · oczekujące awanse: %d" % _captain.learning_points func _build_portrait() -> void: - custom_minimum_size = Vector2(244, 0) + custom_minimum_size = Vector2(244, 72) * PANEL_SCALE var style := StyleBoxFlat.new() - style.bg_color = Color(0.025, 0.042, 0.064, 0.8) - style.border_color = Color("56726e") - style.set_border_width_all(1) - style.set_corner_radius_all(8) - style.set_content_margin_all(6) + style.bg_color = Color(0, 0, 0, 0) add_theme_stylebox_override("panel", style) - var row := HBoxContainer.new() + _frame = load("res://assets/ui/frames/captain_ring_frame.png") as Texture2D + _place($Contents/Header, Rect2(0, 0, 244, 72)) + _place($Contents/Wallet, Rect2(0, 0, 244, 72)) + _place($Contents/Header/Title, Rect2(90, 17, 66, 13)) + $Contents/Header/Title.add_theme_font_size_override("font_size", 9) + _place(level_label, Rect2(175, 17, 52, 13)) + level_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + level_label.add_theme_font_size_override("font_size", 9) + _place(credits_label, Rect2(90, 28, 137, 13)) + credits_label.add_theme_font_size_override("font_size", 11) + credits_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS + _place(xp_label, Rect2(90, 40, 137, 10)) + xp_label.add_theme_font_size_override("font_size", 9) + _place(xp_bar, Rect2(90, 52, 137, 3)) + xp_bar.custom_minimum_size.y = 3 + for part in ["background", "fill"]: + var bar := StyleBoxFlat.new() + bar.bg_color = Color("86d1df") if part == "fill" else Color("122b3788") + bar.set_corner_radius_all(2) + xp_bar.add_theme_stylebox_override(part, bar) + var row := Control.new() row.name = "PortraitRow" - row.add_theme_constant_override("separation", 8) $Contents.add_child(row) - $Contents.move_child(row, 1) - var frame := PanelContainer.new() + var frame := Control.new() frame.name = "AvatarFrame" - var portrait_style := style.duplicate() as StyleBoxFlat - portrait_style.set_content_margin_all(2) - portrait_style.border_color = Color("daa85d") - portrait_style.bg_color = Color("0b1520") - frame.add_theme_stylebox_override("panel", portrait_style) row.add_child(frame) var portrait := TextureRect.new() portrait.name = "CaptainAvatar" portrait.custom_minimum_size = Vector2(54, 54) portrait.expand_mode = TextureRect.EXPAND_IGNORE_SIZE portrait.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED - portrait.mouse_filter = Control.MOUSE_FILTER_IGNORE - if ResourceLoader.exists("res://assets/avatars/captain.png"): - portrait.texture = load("res://assets/avatars/captain.png") + portrait.texture = load("res://assets/avatars/captain.png") + var shader := Shader.new() + shader.code = "shader_type canvas_item; void fragment(){vec4 c = texture(TEXTURE, UV); float mask = 1.0 - smoothstep(0.48, 0.5, distance(UV, vec2(0.5))); COLOR = vec4(c.rgb, c.a * mask);}" + var material := ShaderMaterial.new() + material.shader = shader + portrait.material = material frame.add_child(portrait) - var info := VBoxContainer.new() - info.size_flags_horizontal = Control.SIZE_EXPAND_FILL - info.alignment = BoxContainer.ALIGNMENT_CENTER - row.add_child(info) - var designation := Label.new() - designation.text = "KLIKNIJ · WYPOSAŻENIE" - designation.add_theme_font_size_override("font_size", 9) - designation.add_theme_color_override("font_color", Color("91dbea")) - info.add_child(designation) - xp_label.reparent(info, false) - xp_bar.reparent(info, false) - xp_bar.custom_minimum_size.y = 5 + _place(portrait, Rect2(16, 12, 54, 54)) + portrait.scale = Vector2.ONE * 0.85 + var artwork := TextureRect.new() + artwork.name = "CaptainFrame" + artwork.texture = _frame + artwork.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + artwork.stretch_mode = TextureRect.STRETCH_SCALE + $Contents.add_child(artwork) + $Contents.move_child(artwork, $Contents.get_child_count() - 1) + _place(artwork, Rect2(0, 0, 244, 72)) + queue_redraw() +func _draw() -> void: + draw_circle(Vector2(36, 36) * PANEL_SCALE, 28 * PANEL_SCALE, Color("0a141b66")) + var glass := StyleBoxFlat.new() + glass.bg_color = Color("0b18254d") + glass.set_corner_radius_all(4) + draw_style_box(glass, Rect2(Vector2(73, 17) * PANEL_SCALE, Vector2(160, 36) * PANEL_SCALE)) diff --git a/scripts/ui/captain_paper_doll.gd b/scripts/ui/captain_paper_doll.gd index fc5f5b4..09ec8a5 100644 --- a/scripts/ui/captain_paper_doll.gd +++ b/scripts/ui/captain_paper_doll.gd @@ -59,7 +59,7 @@ func _draw() -> void: func _background() -> StyleBoxFlat: var style := StyleBoxFlat.new() - style.bg_color = Color("0c1419") + style.bg_color = Color("0c141947") style.border_color = Color("3f514e") style.set_border_width_all(1) style.set_corner_radius_all(6) diff --git a/scripts/ui/captain_skills_ui.gd b/scripts/ui/captain_skills_ui.gd index 737f866..81996c7 100644 --- a/scripts/ui/captain_skills_ui.gd +++ b/scripts/ui/captain_skills_ui.gd @@ -33,7 +33,7 @@ func _ready() -> void: _screen.add_child(_panel) _panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER) _contents = VBoxContainer.new() - _contents.add_theme_constant_override("separation", 14) + _contents.add_theme_constant_override("separation", 7) _panel.add_child(_contents) _bar = HBoxContainer.new() _bar.name = "CaptainActiveSkills" @@ -52,17 +52,17 @@ func _label(text: String, font_size: int, color: Color = Color("dae8ef")) -> Lab var label := Label.new() label.text = text label.add_theme_font_override("font", ThemeDB.fallback_font) - label.add_theme_font_size_override("font_size", font_size) + label.add_theme_font_size_override("font_size", preload("res://scripts/ui/compact_interface.gd").font_size(font_size - 3)) label.add_theme_color_override("font_color", color) return label func _style(border: Color, background: Color, margin: int) -> StyleBoxFlat: var style := StyleBoxFlat.new() - style.bg_color = background + style.bg_color = Color(background, minf(background.a, 0.48)) style.border_color = border style.set_border_width_all(1) - style.set_corner_radius_all(10) - style.set_content_margin_all(margin) + style.set_corner_radius_all(4) + style.set_content_margin_all(mini(margin, 10)) return style func _refresh() -> void: @@ -96,6 +96,7 @@ func _build_management() -> void: var close := Button.new() close.name = "Close" close.text = "WRÓĆ DO LOTU" + BUTTON_STYLE.apply(close, Color("91dbea")) close.pressed.connect(_close) heading.add_child(close) _contents.add_child(_label("POZIOM %d" % _captain.level, 13, Color("91aabd"))) @@ -103,7 +104,7 @@ func _build_management() -> void: _contents.add_child(_label("Wybierz jedną umiejętność. Wybór obowiązuje przez całą rozgrywkę.", 16)) var choices := HBoxContainer.new() choices.name = "Choices" - choices.add_theme_constant_override("separation", 14) + choices.add_theme_constant_override("separation", 7) _contents.add_child(choices) for skill in _captain.skill_offers: choices.add_child(_choice_card(skill)) @@ -121,7 +122,7 @@ func _build_management() -> void: if rank <= 0: continue var row := HBoxContainer.new() - row.custom_minimum_size.x = 260 + row.custom_minimum_size.x = 220 row.tooltip_text = CATALOG.description(skill, rank) owned.add_child(row) row.add_child(_icon(skill, 38)) @@ -142,7 +143,7 @@ func _build_loadout() -> void: _contents.add_child(_label("AKTYWNE SLOTY F1–F5 · MAKSYMALNIE 5 UMIEJĘTNOŚCI", 13, Color("91dbea"))) var row := HBoxContainer.new() row.name = "ActiveSkillLoadout" - row.add_theme_constant_override("separation", 10) + row.add_theme_constant_override("separation", 6) _contents.add_child(row) for slot in CaptainProgress.ACTIVE_SKILL_SLOTS: var column := VBoxContainer.new() @@ -154,7 +155,8 @@ func _build_loadout() -> void: picker.fit_to_longest_item = false picker.custom_minimum_size = Vector2(155, 36) picker.add_theme_font_override("font", ThemeDB.fallback_font) - picker.add_theme_font_size_override("font_size", 12) + BUTTON_STYLE.apply(picker, Color("91aabd")) + picker.add_theme_font_size_override("font_size", 11) picker.add_theme_constant_override("icon_max_width", 26) picker.get_popup().add_theme_constant_override("icon_max_width", 28) picker.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS @@ -188,14 +190,14 @@ func _choice_card(skill: String) -> PanelContainer: var color := Color(data["color"]) var card := PanelContainer.new() card.name = skill - card.custom_minimum_size = Vector2(266, 340) + card.custom_minimum_size = Vector2(240, 270) card.size_flags_horizontal = Control.SIZE_EXPAND_FILL card.add_theme_stylebox_override("panel", _style(color.darkened(0.4), Color("101e2e"), 16)) var body := VBoxContainer.new() - body.add_theme_constant_override("separation", 10) + body.add_theme_constant_override("separation", 6) card.add_child(body) body.add_child(_label("NOWA UMIEJĘTNOŚĆ" if rank == 0 else "ULEPSZENIE %s → %s" % [str(rank), str(next_rank)], 11, color)) - body.add_child(_icon(skill, 76)) + body.add_child(_icon(skill, 54)) var title := _label(data["name"], 19) title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART body.add_child(title) @@ -211,7 +213,7 @@ func _choice_card(skill: String) -> PanelContainer: var select := Button.new() select.name = "Choose" select.text = "WYBIERZ" if rank == 0 else "ULEPSZ DO %s" % ["I", "II", "III"][next_rank - 1] - select.custom_minimum_size.y = 38 + select.custom_minimum_size.y = 30 select.focus_mode = Control.FOCUS_NONE BUTTON_STYLE.apply(select, color) select.pressed.connect(_choose.bind(skill)) @@ -302,7 +304,7 @@ func _layout() -> void: if not is_inside_tree(): return var viewport_size := get_viewport().get_visible_rect().size - var base_size := _panel.get_combined_minimum_size().max(Vector2(884, 180)) + var base_size := _panel.get_combined_minimum_size().max(Vector2(760, 160)) var ui_scale := minf(1.0, minf((viewport_size.x - 32) / base_size.x, (viewport_size.y - 32) / base_size.y)) _panel.size = base_size _panel.scale = Vector2.ONE * ui_scale diff --git a/scripts/ui/compact_interface.gd b/scripts/ui/compact_interface.gd new file mode 100644 index 0000000..6e78a02 --- /dev/null +++ b/scripts/ui/compact_interface.gd @@ -0,0 +1,11 @@ +extends RefCounted +## Shared scale for in-game windows, cards and small HUD labels. +const WINDOW_ALPHA := 0.48 +const CARD_ALPHA := 0.28 +const HUD_ALPHA := 0.38 +const BODY_SIZE := 11 +const TITLE_SIZE := 13 +const CORNER_RADIUS := 4 + +static func font_size(requested: int) -> int: + return clampi(requested, 10, TITLE_SIZE) diff --git a/scripts/ui/compact_interface.gd.uid b/scripts/ui/compact_interface.gd.uid new file mode 100644 index 0000000..6580d47 --- /dev/null +++ b/scripts/ui/compact_interface.gd.uid @@ -0,0 +1 @@ +uid://c52sykb26js2f diff --git a/scripts/ui/crafting_recipe_button.gd b/scripts/ui/crafting_recipe_button.gd index 86b0ee6..31b3f0d 100644 --- a/scripts/ui/crafting_recipe_button.gd +++ b/scripts/ui/crafting_recipe_button.gd @@ -16,6 +16,7 @@ func _ready() -> void: for state in ["normal", "hover", "pressed", "disabled"]: var style := StyleBoxFlat.new() style.bg_color = Color("172b3b") if state == "hover" else Color("0c1925") + style.bg_color.a = minf(style.bg_color.a, 0.64) style.border_color = Color("e7bb73") if state == "hover" else Color("314b60") style.set_border_width_all(1) style.set_corner_radius_all(7) @@ -79,7 +80,8 @@ func refresh() -> void: func _make_custom_tooltip(_text: String) -> Object: var panel := PanelContainer.new() var style := StyleBoxFlat.new() - style.bg_color = Color("0a1522") + style.bg_color = Color("0a1522b8") + style.bg_color.a = minf(style.bg_color.a, 0.64) style.border_color = Color("bc975f") style.set_border_width_all(1) style.set_corner_radius_all(7) diff --git a/scripts/ui/defeat_overlay.gd b/scripts/ui/defeat_overlay.gd index 7277874..9cd8e36 100644 --- a/scripts/ui/defeat_overlay.gd +++ b/scripts/ui/defeat_overlay.gd @@ -19,7 +19,7 @@ func _ready() -> void: var panel := PanelContainer.new() panel.custom_minimum_size.x = 390 var style := StyleBoxFlat.new() - style.bg_color = Color("0b1520f5") + style.bg_color = Color("0b152094") style.border_color = Color("bf604d") style.set_border_width_all(1) style.border_width_top = 3 @@ -33,7 +33,7 @@ func _ready() -> void: var title := Label.new() title.text = "STATEK ZNISZCZONY" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - title.add_theme_font_size_override("font_size", 20) + title.add_theme_font_size_override("font_size", 16) title.add_theme_color_override("font_color", Color("ffae8c")) contents.add_child(title) var note := Label.new() diff --git a/scripts/ui/enemy_drawer.gd b/scripts/ui/enemy_drawer.gd index 9c3afec..1917e54 100644 --- a/scripts/ui/enemy_drawer.gd +++ b/scripts/ui/enemy_drawer.gd @@ -6,8 +6,10 @@ func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE _label = Label.new() _label.name = "EnemyDetails" + _label.add_theme_constant_override("line_spacing", -2) + _label.add_theme_font_override("font", ThemeDB.fallback_font) _label.mouse_filter = Control.MOUSE_FILTER_IGNORE - _label.add_theme_font_size_override("font_size", 9) + _label.add_theme_font_size_override("font_size", 8) _label.add_theme_color_override("font_color", Color("c9acb5")) _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _label.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) @@ -21,7 +23,7 @@ func _process(_delta: float) -> void: var profile := DamageTypes.enemy_profile(GameState.system_level, GameState.system_seed) var kind := int(profile["kind"]) var names := ["Działko plazmowe", "Działko maszynowe", "Laser", "Rakiety", "Działko gamma"] - _label.text = "%s\n%s" % [names[kind], DamageTypes.describe(profile["absorption"])] + _label.text = "%s\n%s" % [names[kind], "K %.1f%% · E %.1f%% · R %.1f%%" % [profile["absorption"].x, profile["absorption"].y, profile["absorption"].z]] if enemy != null: _label.text += "\nDPS: %.1f (%s)\nTarcze: %.0f / %.0f" % [enemy.get_weapon_dps(), ["zwykły", "elita", "boss"][enemy.loot_tier], enemy.shields, enemy.max_shields] else: diff --git a/scripts/ui/equipment_slot_view.gd b/scripts/ui/equipment_slot_view.gd index 7f88dcc..7ef444f 100644 --- a/scripts/ui/equipment_slot_view.gd +++ b/scripts/ui/equipment_slot_view.gd @@ -26,7 +26,7 @@ func _ready() -> void: _delete_button.tooltip_text = "Rozłóż przedmiot: +10 części" _delete_button.focus_mode = Control.FOCUS_NONE var tool_style := StyleBoxFlat.new() - tool_style.bg_color = Color(0.04, 0.07, 0.1, 0.96) + tool_style.bg_color = Color(0.04, 0.07, 0.1, 0.72) tool_style.border_color = Color("b68c53") tool_style.set_border_width_all(1) tool_style.set_corner_radius_all(3) @@ -106,7 +106,7 @@ func _refresh() -> void: slot_label.visible = true slot_label.text = "BLOKADA" slot_label.add_theme_color_override("font_color",Color("9a795b")) - tooltip_text = "Rząd zablokowany. Odblokuj kolejny rząd w hangarze za 10 żelaza." if slot_kind == "cargo" else "Slot zablokowany. Odblokuj w hangarze fregaty za 10 żelaza." + tooltip_text = "Slot zablokowany. Odblokowuj kolejne miejsca w hangarze fregaty.\nNastępny slot: " + _inventory.get_slot_unlock_cost_text(slot_kind) _update_salvage_visibility() return _icon.texture = item.definition.icon if item != null and item.definition != null else _empty_icon() @@ -155,7 +155,7 @@ func _make_custom_tooltip(for_text: String) -> Object: var panel := PanelContainer.new() panel.set_script(preload("res://scripts/ui/item_tooltip_frame.gd")) var background := StyleBoxFlat.new() - background.bg_color = Color("101925") + background.bg_color = Color("101925b8") background.border_color = Color("52677e") background.set_border_width_all(1) background.border_width_top = 2 @@ -177,6 +177,7 @@ func _make_custom_tooltip(for_text: String) -> Object: if item: # Dark neutral body with an accent tied to the equipment category. background.bg_color = Color("0c1520").lerp(item.get_background_color().darkened(0.8), 0.25) + background.bg_color.a = 0.72 background.border_color = item.get_type_color() panel.set("accent", item.get_type_color()) var columns := HBoxContainer.new() @@ -191,7 +192,7 @@ func _make_custom_tooltip(for_text: String) -> Object: if item != null: var header_frame := PanelContainer.new() var header_style := StyleBoxFlat.new() - header_style.bg_color = item.get_type_color().darkened(0.8) + header_style.bg_color = Color(item.get_type_color().darkened(0.8), 0.45) header_style.border_color = item.get_type_color().darkened(0.35) header_style.border_width_left = 3 header_style.set_content_margin_all(8) diff --git a/scripts/ui/flight_cockpit.gd b/scripts/ui/flight_cockpit.gd index 778f41a..92701f9 100644 --- a/scripts/ui/flight_cockpit.gd +++ b/scripts/ui/flight_cockpit.gd @@ -4,18 +4,25 @@ const FONT := preload("res://assets/fonts/font2.ttf") const CYAN := Color("91dbea") const WEAPON_DISPLAY_ORDER := [0, 2, 1] const AMBER := Color("efb568") +const DESIGN_SIZE := Vector2(850, 144) +const SCREENS := [Rect2(80, 33, 155, 73), Rect2(272, 33, 304, 73), Rect2(619, 33, 157, 73)] var player: CharacterBody2D var game: Node2D var _enemy_details: Control var _inventory: ShipInventory +var _frame: Texture2D +var _frame_region := Rect2(1, 110, 2171, 459) func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE + _frame = load("res://assets/ui/frames/cockpit_console.png") as Texture2D _inventory = player.get_node("ShipInventory") _enemy_details = Control.new() _enemy_details.name = "EnemyDetailsPanel" _enemy_details.set_script(preload("res://scripts/ui/enemy_drawer.gd")) add_child(_enemy_details) + _enemy_details.position = Vector2(625, 64) + _enemy_details.size = Vector2(145, 42) func _process(delta: float) -> void: if is_instance_valid(player): @@ -23,62 +30,57 @@ func _process(delta: float) -> void: var local := get_global_transform().affine_inverse() * screen var overlaps := Rect2(Vector2.ZERO, size).grow(36).has_point(local) modulate.a = move_toward(modulate.a, 0.18 if overlaps else 1.0, delta * 4.0) - var cell := (size.x - 238) / 3.0 - _enemy_details.position = Vector2(218.0 + 2.0 * cell, 57) - _enemy_details.size = Vector2(cell, 56) queue_redraw() +func fitted_font_size(value: String, width: float, requested: int) -> int: + var result := requested + while result > 7 and FONT.get_string_size(value, HORIZONTAL_ALIGNMENT_LEFT, -1, result).x > width: + result -= 1 + return result + func _text(value: String, point: Vector2, width: float, font_size: int, color: Color) -> void: - draw_string(FONT, point, value, HORIZONTAL_ALIGNMENT_CENTER, width, font_size, color) + var fitted := fitted_font_size(value, width, font_size) + draw_string_outline(FONT, point, value, HORIZONTAL_ALIGNMENT_CENTER, width, fitted, 2, Color("030a12cc")) + draw_string(FONT, point, value, HORIZONTAL_ALIGNMENT_CENTER, width, fitted, color) func _draw() -> void: - if _inventory == null or not is_instance_valid(player) or size.x < 50 or size.y < 50: - return - var outline := PackedVector2Array([Vector2(24, 0), Vector2(size.x - 24, 0), Vector2(size.x, 24), Vector2(size.x, size.y - 12), Vector2(size.x - 12, size.y), Vector2(12, size.y), Vector2(0, size.y - 12), Vector2(0, 24)]) - draw_colored_polygon(outline, Color(0.025, 0.041, 0.063, 0.78)) - var closed := outline.duplicate() - closed.append(outline[0]) - draw_polyline(closed, Color("376779"), 1.5, true) - draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true) - # Put weapon cards beside the counters rather than stacking three rows. - _text("DPS: %.1f" % _inventory.get_total_dps(), Vector2(20, 81), 172, 12, CYAN) - _text("PRĘDKOŚĆ: %.0f" % player.velocity.length(), Vector2(20, 101), 172, 11, Color("c4d6df")) - var absorption: Vector3 = player.get("absorption") + if _inventory == null or not is_instance_valid(player): return + for screen in SCREENS: + var glass := StyleBoxFlat.new() + glass.bg_color = Color("07151e66") + glass.set_corner_radius_all(3) + draw_style_box(glass, screen) + draw_texture_rect_region(_frame, Rect2(Vector2.ZERO, DESIGN_SIZE), _frame_region) for index in 3: - _text("%s - %.1f%%" % [DamageTypes.NAMES[index], absorption[index]], Vector2(205, 77 + index * 15), 2.0 * (size.x - 238) / 3.0, 11, Color("a9d69a")) - var cell := (size.x - 238) / 3.0 - var values := [_inventory.missile_ammunition, _inventory.ammunition, int(game.call("get_remaining_enemies"))] - var captions := ["RAKIETY", "AMUNICJA", "WROGOWIE"] - var boss_alive := bool(game.call("is_boss_alive")) - for index in 3: - var x := 218.0 + index * cell - var color := AMBER if index == 0 else (CYAN if index == 1 else Color("ff8989")) - _text(captions[index], Vector2(x, 21), cell, 9, Color("8aa9bb")) - if index == 1: - _text("ZWYKŁE %02d" % _inventory.ammunition, Vector2(x, 35), cell, 11, CYAN) - _text("GAMMA %02d" % _inventory.irradiated_ammunition, Vector2(x, 49), cell, 11, Color("a9ef83")) - elif index == 2 and boss_alive: - _text("BOSS", Vector2(x, 45), cell, 21, Color("ff8989")) - else: - _text(str(values[index]).pad_zeros(2), Vector2(x, 45), cell, 21, color) - if index < 2: - draw_line(Vector2(x + cell, 14), Vector2(x + cell, 45), Color("2b4354"), 1) - var card := Rect2(20 + index * 60, 12, 52, 52) + var card := Rect2(85 + index * 48, 37, 43, 41) var slot_index: int = WEAPON_DISPLAY_ORDER[index] - var item := _inventory.get_item("weapon",slot_index) + var item := _inventory.get_item("weapon", slot_index) var border := item.get_type_color() if item != null else Color("344657") draw_style_box(_card_style(border), card) var binding: String = ["LPM", "PPM", "ŚPM"][slot_index] - _text(binding, card.position + Vector2(0, 12), card.size.x, 9, CYAN) + _text(binding, card.position + Vector2(0, 10), card.size.x, 8, CYAN) if item != null and item.definition.icon != null: - draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(9, 16), Vector2(34, 34)), false) + draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(8, 13), Vector2(27, 27)), false) else: - _text("—" if _inventory.is_slot_unlocked("weapon",slot_index) else "X", card.position + Vector2(0, 36), card.size.x, 14, Color("637d90")) + _text("—" if _inventory.is_slot_unlocked("weapon", slot_index) else "X", card.position + Vector2(0, 31), card.size.x, 12, Color("637d90")) + _text("DPS: %.1f" % _inventory.get_total_dps(), Vector2(85, 91), 145, 10, CYAN) + _text("PRĘDKOŚĆ: %.0f" % player.velocity.length(), Vector2(85, 103), 145, 9, Color("c4d6df")) + _text("RAKIETY", Vector2(280, 44), 100, 8, Color("8aa9bb")) + _text(str(_inventory.missile_ammunition).pad_zeros(2), Vector2(280, 66), 100, 19, AMBER) + _text("AMUNICJA", Vector2(385, 44), 182, 8, Color("8aa9bb")) + _text("ZWYKŁE %02d" % _inventory.ammunition, Vector2(385, 59), 182, 10, CYAN) + _text("GAMMA %02d" % _inventory.irradiated_ammunition, Vector2(385, 72), 182, 10, Color("a9ef83")) + var absorption: Vector3 = player.get("absorption") + for index in 3: + _text("%s: %.1f%%" % [DamageTypes.NAMES[index], absorption[index]], Vector2(280, 85 + index * 10), 287, 9, Color("a9d69a")) + _text("WROGOWIE", Vector2(625, 44), 145, 8, Color("8aa9bb")) + var remaining := "BOSS" if bool(game.call("is_boss_alive")) else str(int(game.call("get_remaining_enemies"))).pad_zeros(2) + _text(remaining, Vector2(625, 61), 145, 17, Color("ff8989")) func _card_style(color: Color) -> StyleBoxFlat: var style := StyleBoxFlat.new() - style.bg_color = Color("0b1520") + style.bg_color = Color("0b15205c") style.border_color = color style.set_border_width_all(1) - style.set_corner_radius_all(4) + style.set_corner_radius_all(3) return style diff --git a/scripts/ui/hud_button_style.gd b/scripts/ui/hud_button_style.gd index bbdc0d1..5d4b693 100644 --- a/scripts/ui/hud_button_style.gd +++ b/scripts/ui/hud_button_style.gd @@ -2,7 +2,7 @@ extends RefCounted static func apply(button: Button, accent: Color = Color("91dbea")) -> void: button.focus_mode = Control.FOCUS_NONE - button.add_theme_font_size_override("font_size", 12) + button.add_theme_font_size_override("font_size", 11) button.add_theme_color_override("font_color", accent.lightened(0.25)) button.add_theme_color_override("font_hover_color", Color.WHITE) button.add_theme_color_override("font_pressed_color", Color.WHITE) @@ -15,15 +15,15 @@ static func apply(button: Button, accent: Color = Color("91dbea")) -> void: static func _style(background: Color, border: Color) -> StyleBoxFlat: var style := StyleBoxFlat.new() - style.bg_color = background + style.bg_color = Color(background, 0.48) style.border_color = border style.set_border_width_all(1) style.border_width_left = 3 - style.set_corner_radius_all(7) + style.set_corner_radius_all(4) style.content_margin_left = 14 style.content_margin_right = 14 - style.content_margin_top = 6 - style.content_margin_bottom = 6 + style.content_margin_top = 4 + style.content_margin_bottom = 4 style.shadow_color = Color(0, 0, 0, 0.24) style.shadow_size = 3 style.shadow_offset = Vector2(0, 2) diff --git a/scripts/ui/inventory_resource_card.gd b/scripts/ui/inventory_resource_card.gd index 0036bfc..f860b80 100644 --- a/scripts/ui/inventory_resource_card.gd +++ b/scripts/ui/inventory_resource_card.gd @@ -36,6 +36,7 @@ func _ready() -> void: func _style(hovered: bool) -> StyleBoxFlat: var style := StyleBoxFlat.new() style.bg_color = Color("172737") if hovered else Color("0c1723") + style.bg_color.a = 0.36 style.border_color = accent if hovered else accent.darkened(0.65) style.set_border_width_all(1) style.set_corner_radius_all(4) diff --git a/scripts/ui/mission_objectives.gd b/scripts/ui/mission_objectives.gd index f1a5884..2454b11 100644 --- a/scripts/ui/mission_objectives.gd +++ b/scripts/ui/mission_objectives.gd @@ -6,20 +6,20 @@ var _objective: Label func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE var style := StyleBoxFlat.new() - style.bg_color = Color(0.025, 0.041, 0.063, 0.72) + style.bg_color = Color(0.025, 0.041, 0.063, 0.38) style.border_color = Color("376779") style.set_border_width_all(1) style.set_corner_radius_all(6) - style.set_content_margin_all(12) + style.set_content_margin_all(8) add_theme_stylebox_override("panel", style) var contents := VBoxContainer.new() contents.mouse_filter = Control.MOUSE_FILTER_IGNORE - contents.add_theme_constant_override("separation", 6) + contents.add_theme_constant_override("separation", 3) add_child(contents) var title := Label.new() title.text = "CELE" title.mouse_filter = Control.MOUSE_FILTER_IGNORE - title.add_theme_font_size_override("font_size", 12) + title.add_theme_font_size_override("font_size", 10) title.add_theme_color_override("font_color", Color("91dbea")) contents.add_child(title) _objective = Label.new() diff --git a/scripts/ui/orbital_contact_style.gd b/scripts/ui/orbital_contact_style.gd index 9d93fa9..7ad2ff2 100644 --- a/scripts/ui/orbital_contact_style.gd +++ b/scripts/ui/orbital_contact_style.gd @@ -2,7 +2,7 @@ extends RefCounted ## Compact translucent cards attached to objects in the world canvas. static func panel_style(accent: Color) -> StyleBoxFlat: var style := StyleBoxFlat.new() - style.bg_color = Color(0.018,0.041,0.063,0.84) + style.bg_color = Color(0.018,0.041,0.063,0.48) style.border_color = Color(accent,0.55) style.set_border_width_all(1) style.border_width_top = 2 @@ -22,7 +22,7 @@ static func compact_button(button: Button, accent: Color) -> void: button.add_theme_font_size_override("font_size",11) for state in ["normal","hover","pressed","disabled"]: var style := button.get_theme_stylebox(state).duplicate() as StyleBoxFlat - style.bg_color.a = 0.8 + style.bg_color.a = 0.50 style.content_margin_top = 4 style.content_margin_bottom = 4 style.content_margin_left = 9 diff --git a/scripts/ui/ornamental_frame.gd b/scripts/ui/ornamental_frame.gd new file mode 100644 index 0000000..41322cc --- /dev/null +++ b/scripts/ui/ornamental_frame.gd @@ -0,0 +1,34 @@ +extends Node2D +## Draw only the eight border patches, preserving transparency and corner proportions. +const TEXTURE_PATH := "res://assets/ui/frames/ship_ornament.png" +var corner_size := 16.0 +var opacity := 0.9 +var _texture: Texture2D +var _region: Rect2 + +func _ready() -> void: + name = "OrnamentalFrame" + z_index = 1 + _texture = load(TEXTURE_PATH) + var source := _texture.get_image() + if source.is_compressed(): source.decompress() + _region = Rect2(source.get_used_rect()) + (get_parent() as Control).resized.connect(queue_redraw) + queue_redraw() + +func _draw() -> void: + if _texture == null: return + var extent: Vector2 = (get_parent() as Control).size + var edge := minf(corner_size, minf(extent.x, extent.y) * 0.25) + var source_x := _region.size.x * 0.1 + var source_y := _region.size.y * 0.18 + var sx := [0.0, source_x, _region.size.x - source_x, _region.size.x] + var sy := [0.0, source_y, _region.size.y - source_y, _region.size.y] + var dx := [0.0, edge, extent.x - edge, extent.x] + var dy := [0.0, edge, extent.y - edge, extent.y] + for y in range(3): + for x in range(3): + if x == 1 and y == 1: continue + var destination := Rect2(Vector2(dx[x],dy[y]),Vector2(dx[x+1]-dx[x],dy[y+1]-dy[y])) + var source := Rect2(_region.position + Vector2(sx[x],sy[y]),Vector2(sx[x+1]-sx[x],sy[y+1]-sy[y])) + draw_texture_rect_region(_texture,destination,source,Color(1,1,1,opacity)) diff --git a/scripts/ui/ornamental_frame.gd.uid b/scripts/ui/ornamental_frame.gd.uid new file mode 100644 index 0000000..3a02aff --- /dev/null +++ b/scripts/ui/ornamental_frame.gd.uid @@ -0,0 +1 @@ +uid://cgd0v6sbthdqb diff --git a/scripts/ui/passive_status_panel.gd b/scripts/ui/passive_status_panel.gd index 6a4fc68..6f2bc8e 100644 --- a/scripts/ui/passive_status_panel.gd +++ b/scripts/ui/passive_status_panel.gd @@ -5,7 +5,7 @@ var caption := "PASYWNE" func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE var frame := StyleBoxFlat.new() - frame.bg_color = Color(0.025, 0.041, 0.063, 0.55) + frame.bg_color = Color(0.025, 0.041, 0.063, 0.30) frame.border_color = Color(0.28, 0.48, 0.55, 0.45) frame.set_border_width_all(1) frame.set_corner_radius_all(6) diff --git a/scripts/ui/planet_services_menu.gd b/scripts/ui/planet_services_menu.gd index ecadeaf..0d870e2 100644 --- a/scripts/ui/planet_services_menu.gd +++ b/scripts/ui/planet_services_menu.gd @@ -144,7 +144,7 @@ func _add_offer(offers: HBoxContainer, button: Button, item_id: String, caption: func show_services(at_level_cap: bool, portal_open: bool = false) -> void: _refresh_ammunition_service() next_button.disabled = at_level_cap or portal_open - next_button.text = "OSTATNI UKŁAD" if at_level_cap else ("WORMHOLE OTWARTY" if portal_open else "OTWÓRZ WORMHOLE") + next_button.text = "OSTATNI UKŁAD" if at_level_cap else ("WORMHOLE OTWARTY" if portal_open else ("PRZEJDŹ DO HARD" if GameState.system_level == preload("res://scripts/levels/level_balance.gd").NORMAL_MAX_LEVEL else "OTWÓRZ WORMHOLE")) status_label.text = "Wleć w wormhole, aby przejść dalej." if portal_open else "Bezpieczny układ · zaopatrzenie" if visible: return diff --git a/scripts/ui/player_guide.gd b/scripts/ui/player_guide.gd index 47d2931..9572d7a 100644 --- a/scripts/ui/player_guide.gd +++ b/scripts/ui/player_guide.gd @@ -3,13 +3,13 @@ extends Control signal closed const BUTTON_STYLE := preload("res://scripts/ui/hud_button_style.gd") const PAGES := [ - ["Pierwsza wyprawa", "01", "[font_size=26][color=#f1bd79]Twój pierwszy układ[/color][/font_size]\n\nWybierz statek przyciskiem [b]Nowa wyprawa[/b]. Każdy kadłub ma inne parametry — na początek wybierz ten, który pasuje do Twojego stylu.\n\n[color=#91dbea][b]1. Pokonaj zwykłych wrogów[/b][/color]\nOdszukuj przeciwników, rozwijaj wyposażenie i pilnuj zasobów. Aktualny cel znajdziesz w lewym dolnym rogu ekranu.\n\n[color=#91dbea][b]2. Pokonaj bossa[/b][/color]\nGdy zniszczysz pozostałych wrogów, w układzie pojawi się boss. Przygotuj zapas amunicji i sprawdź kadłub przed walką.\n\n[color=#91dbea][b]3. Znajdź zamieszkaną planetę[/b][/color]\nPo zwycięstwie podleć do zamieszkanej planety. Skorzystaj z usług i otwórz wormhole. Wleć w jego środek, żeby przejść do następnego, trudniejszego układu."], - ["Sterowanie", "02", "[font_size=26][color=#f1bd79]Opanuj statek[/color][/font_size]\n\n[color=#91dbea][b]W[/b][/color] — ciąg do przodu.\n[color=#91dbea][b]S[/b][/color] — hamowanie; po zatrzymaniu lot wstecz.\n[color=#91dbea][b]A / D[/b][/color] — obracanie statku.\n[color=#91dbea][b]Q / E[/b][/color] — ruch boczny w lewo / prawo.\n[color=#91dbea][b]TAB[/b][/color] — dopalanie: większa prędkość kosztem energii.\n\n[color=#91dbea][b]Kursor myszy[/b][/color] — celowanie.\n[color=#91dbea][b]LPM / PPM / ŚPM[/b][/color] — strzelanie z trzech slotów broni.\n[color=#91dbea][b]1–5[/b][/color] — użycie zamontowanych rozszerzeń.\n[color=#91dbea][b]F1–F5[/b][/color] — aktywne umiejętności kapitana.\n[color=#91dbea][b]R[/b][/color] — użycie powerbanku, jeśli masz go w zapasach.\n\nStatek ma bezwładność. Obrót nie zatrzymuje ruchu — hamuj wcześniej i wykorzystuj ruch boczny, żeby unikać ostrzału."], - ["Walka i przetrwanie", "03", "[font_size=26][color=#f1bd79]Wróć z wyprawy[/color][/font_size]\n\n[color=#91dbea][b]Tarcze, kadłub i energia[/b][/color]\nTarcze pochłaniają obrażenia przed kadłubem. Utrata całego kadłuba oznacza zniszczenie statku. Energia zasila część broni oraz dopalanie; odnawia się z czasem, szybciej przy gwieździe.\n\n[color=#91dbea][b]Dobieraj broń do zapasów[/b][/color]\nBroń energetyczna zużywa energię. Działko maszynowe potrzebuje zwykłej amunicji, gamma — napromieniowanej, a wyrzutnie — rakiet. Puste zapasy oznaczają brak strzału. Absorpcja ogranicza obrażenia danego typu.\n\n[color=#91dbea][b]Korzystaj z rozszerzeń[/b][/color]\nMiny atakują obszarowo, flary odciągają uwagę, kamuflaż pomaga zerwać kontakt, teleport przenosi w bezpieczne miejsce, a drony wspierają ostrzał. Doładowanie tarcz działa przy gwieździe. Sprawdzaj koszt i cooldown w opisie.\n\n[color=#f1bd79][b]Uważaj na uciekających przeciwników[/b][/color]\nWróg z kadłubem poniżej 10% ucieka wolniej, ale może zostawić minę. Nie leć bezmyślnie prosto za nim."], - ["Łup i wytwarzanie", "04", "[font_size=26][color=#f1bd79]Zbieraj. Porównuj. Twórz.[/color][/font_size]\n\n[color=#91dbea][b]Łup zbierasz przez podlecenie[/b][/color]\nPrzedmioty w pobliżu są przyciągane do statku. Magazyn mieści 20 przedmiotów; przy pełnym magazynie zwolnij miejsce, żeby zebrać kolejny.\n\n[color=#91dbea][b]Asteroidy zostawiają fizyczne odłamki[/b][/color]\nStrzelaj do asteroid. Po zniszczeniu rozpadają się bazowo na 5–7 poszarpanych fragmentów. Każdy to jedna jednostka surowca — musisz go zebrać. Umiejętność górnika zwiększa uzysk.\n\n[color=#91dbea][b]Przeszukuj wraki[/b][/color]\nPodleć do wraku i przytrzymaj E, aby go przeszukać. Wraki dają surowce (65%), amunicję lub rakiety (łącznie 20%) albo moduł (15%).\n\n[color=#91dbea][b]Warsztat fregaty — produkcja[/b][/color]\nZadokuj na fregacie i wybierz Warsztat. Tam wytworzysz amunicję, rakiety, części, powerbanki i wyposażenie kapitana. Koszt sprawdzisz w podpowiedzi przycisku produkcji.\n\n[color=#91dbea][b]Odzyskuj części[/b][/color]\nNajedź na zbędny przedmiot w magazynie i użyj przycisku rozłożenia. Części przydadzą się do napraw."], - ["Statek i kapitan", "05", "[font_size=26][color=#f1bd79]Buduj własny styl gry[/color][/font_size]\n\n[color=#91dbea][b]Wyposażenie[/b][/color]\nKliknij panel statku w prawym górnym rogu i otwórz magazyn. Przeciągaj przedmioty do pasujących slotów: maksymalnie 3 bronie, 5 modułów i 5 rozszerzeń. Na początku dostępny jest 1 slot broni i 1 rozszerzenia. Kolejne odblokowujesz w hangarze fregaty za 10 żelaza każdy. Ładownia zaczyna z jednym rzędem (5 miejsc); kolejne rzędy kupujesz w hangarze po 10 żelaza. Po zbudowaniu składu modułów zakładka Magazyn na frachtowcu pozwala odkładać i odbierać wyposażenie. Aktywne rozszerzenia uruchamiasz klawiszami 1–5; pasywne (oznaczone P) działają automatycznie w tych samych slotach. Najedź kursorem, żeby sprawdzić parametry i porównanie wyposażenia.\n\n[color=#91dbea][b]Nie każdy duplikat jest taki sam[/b][/color]\nBroń i moduły mogą mieć różne parametry oraz addony. Aktywne rozszerzenia losują cooldown od 30 do 5 pełnych sekund. Pasywne mają losowaną siłę efektu: Recykler odnawia tarcze i energię po zebraniu odłamka, Wirus przejmuje uciekających wrogów, a Pancerz z tytanu ogranicza obrażenia przy niskim kadłubie. Krótsze odnowienia są rzadkie — przed rozłożeniem porównaj egzemplarze. Rozszerzenia tego samego typu dzielą aktywne odnowienie.\n\n[color=#91dbea][b]Umiejętności kapitana[/b][/color]\nZa pokonanych wrogów zdobywasz doświadczenie i kredyty. Trudniejsze układy dają więcej bazowego XP. Jeśli kapitan przewyższa poziom układu o ponad 2 poziomy, XP za przeciwników i ruiny maleje; przy przewadze 8 poziomów spada do zera. Kredyty i surowce nadal zbierasz. Po awansie wybierasz umiejętność. Pasywne działają stale, aktywne przypisujesz do F1–F5.\n\n[color=#f1bd79][b]Okno umiejętności nie pauzuje gry.[/b][/color]\nOtwieraj je w bezpiecznym miejscu. Przed kolejnym układem uzupełnij zapasy i sprawdź wyposażenie."] - ,["Planety i frachtowiec", "06", "[font_size=26][color=#f1bd79]Wyprawa na powierzchnię[/color][/font_size]\n\nPodleć do planety oznaczonej EARTHLIKE. [b]F[/b] skanuje tlen, temperaturę i zagrożenie biologiczne. [b]L[/b] rozpoczyna lądowanie. Możesz eksplorować przed pokonaniem wrogów, ale lądowanie jest zablokowane podczas walki.\n\nLądownik wymaga 100 HP przed startem i traci 5–20 HP przy wejściu w atmosferę. Na powierzchni sterujesz jak statkiem: [b]W[/b] — ciąg, [b]S[/b] — hamowanie i wstecz, [b]A/D[/b] — obrót, [b]Q/E[/b] — ruch boczny, [b]TAB[/b] — dopalanie. Odkrywaj miejsca i używaj [b]F[/b], aby je zbadać. Lądownik ma osobną energię dopalania. Każdy etap badania pokazuje szansę sukcesu; dalsze etapy dają więcej łupu i większe ryzyko.\n\n[b]L[/b] lub przycisk powrotu kończy wyprawę i przenosi łup do Twoich zasobów. Zniszczenie lądownika oznacza utratę tylko zdobyczy tej wyprawy. Kolejne lądowanie tworzy nową mapę.\n\n[color=#91dbea][b]Frachtowiec[/b][/color]\nZnajdziesz go przy gwieździe centralnej. Podleć i naciśnij [b]L[/b]. Hangar naprawia lądownik (1 część za 1% HP), warsztat prowadzi całą produkcję amunicji, rakiet, zaopatrzenia i sprzętu kapitana, a laboratorium przechowuje skany i archiwa.\n\nKapitan zaczyna z podstawowym systemem oddychania, skafandrem i bronią ręczną. Kolejne poziomy tworzysz w warsztacie; posiadany sprzęt zmienisz w Warsztacie. Kliknięcie panelu kapitana pokazuje sylwetkę, założone przedmioty i redukcję zagrożeń nad slotami. Wyższy poziom poprawia szanse eksploracji.\n\n[color=#91dbea][b]Losowe spotkania[/b][/color]\nPytajnik na mapie oznacza wydarzenie. Podleć, aby otworzyć okno. Miejscowy inżynier może zaoferować nieznany moduł za 100 kredytów. Wyższe poziomy przedmiotów są coraz rzadsze. Kupiony moduł pozostaje w ładowni wyprawy do bezpiecznego powrotu.\n\n[color=#f1bd79]Podczas wyprawy i wizyty we frachtowcu kosmos jest zamrożony. Zapisywanie między uruchomieniami gry nie jest jeszcze dostępne.[/color]"] -, ["Autorzy dźwięków", "07", "[font_size=26][color=#f1bd79]Dźwięki otoczenia[/color][/font_size]\n\n[b]Blender Foundation — Ambient Bird, Cricket and Frog (Yo Frankie!)[/b]\nOdgłosy świerszcza i żaby, udostępnione przez Lamoot:\nhttps://opengameart.org/content/ambient-bird-cricket-and-frog\nLicencja Creative Commons Attribution 3.0:\nhttps://creativecommons.org/licenses/by/3.0/\nZmiany: filtrowanie, płynne początki i zakończenia, zmiana wysokości żaby oraz konwersja do stereo 48 kHz. Autorzy nie są powiązani z tą grą.\n\n[b]Nagrania na licencji CC0[/b]\nThimras — Park ambiences (wiatr).\nIwan „qubodup” Gabovitch — 20 Rustles of dry leaves.\nisaiah658 — Ambient Bird Sounds.\nRudmer_Rotteveel — Wood Creak Single V7.\n\n[b]Wnętrze fregaty — CC0[/b]\nLEGIT Audio — The Shop (bezpłatne próbki OpenGameArt).\nbart — 68 Workshop Sounds i Steam release sounds.\nKenney — Sci-Fi Sounds.\n\nSzczegółowe źródła i zakres obróbki znajdują się w plikach CREDITS.md i manifest.json przy zasobach audio."] + ["Pierwsza wyprawa", "01", "[font_size=16][color=#f1bd79]Twój pierwszy układ[/color][/font_size]\n\nWybierz statek przyciskiem [b]Nowa wyprawa[/b]. Każdy kadłub ma inne parametry — na początek wybierz ten, który pasuje do Twojego stylu.\n\n[color=#91dbea][b]1. Pokonaj zwykłych wrogów[/b][/color]\nOdszukuj przeciwników, rozwijaj wyposażenie i pilnuj zasobów. Aktualny cel znajdziesz w lewym dolnym rogu ekranu.\n\n[color=#91dbea][b]2. Pokonaj bossa[/b][/color]\nGdy zniszczysz pozostałych wrogów, w układzie pojawi się boss. Przygotuj zapas amunicji i sprawdź kadłub przed walką.\n\n[color=#91dbea][b]3. Znajdź zamieszkaną planetę[/b][/color]\nPo zwycięstwie podleć do zamieszkanej planety. Skorzystaj z usług i otwórz wormhole. Wleć w jego środek, żeby przejść do następnego, trudniejszego układu."], + ["Sterowanie", "02", "[font_size=16][color=#f1bd79]Opanuj statek[/color][/font_size]\n\n[color=#91dbea][b]W[/b][/color] — ciąg do przodu.\n[color=#91dbea][b]S[/b][/color] — hamowanie; po zatrzymaniu lot wstecz.\n[color=#91dbea][b]A / D[/b][/color] — obracanie statku.\n[color=#91dbea][b]Q / E[/b][/color] — ruch boczny w lewo / prawo.\n[color=#91dbea][b]TAB[/b][/color] — dopalanie: większa prędkość kosztem energii.\n\n[color=#91dbea][b]Kursor myszy[/b][/color] — celowanie.\n[color=#91dbea][b]LPM / PPM / ŚPM[/b][/color] — strzelanie z trzech slotów broni.\n[color=#91dbea][b]1–5[/b][/color] — użycie zamontowanych rozszerzeń.\n[color=#91dbea][b]F1–F5[/b][/color] — aktywne umiejętności kapitana.\n[color=#91dbea][b]R[/b][/color] — użycie powerbanku, jeśli masz go w zapasach.\n\nStatek ma bezwładność. Obrót nie zatrzymuje ruchu — hamuj wcześniej i wykorzystuj ruch boczny, żeby unikać ostrzału."], + ["Walka i przetrwanie", "03", "[font_size=16][color=#f1bd79]Wróć z wyprawy[/color][/font_size]\n\n[color=#91dbea][b]Tarcze, kadłub i energia[/b][/color]\nTarcze pochłaniają obrażenia przed kadłubem. Utrata całego kadłuba oznacza zniszczenie statku. Energia zasila część broni oraz dopalanie; odnawia się z czasem, szybciej przy gwieździe.\n\n[color=#91dbea][b]Dobieraj broń do zapasów[/b][/color]\nBroń energetyczna zużywa energię. Działko maszynowe potrzebuje zwykłej amunicji, gamma — napromieniowanej, a wyrzutnie — rakiet. Puste zapasy oznaczają brak strzału. Absorpcja ogranicza obrażenia danego typu.\n\n[color=#91dbea][b]Korzystaj z rozszerzeń[/b][/color]\nMiny atakują obszarowo, flary odciągają uwagę, kamuflaż pomaga zerwać kontakt, teleport przenosi w bezpieczne miejsce, a drony wspierają ostrzał. Doładowanie tarcz działa przy gwieździe. Sprawdzaj koszt i cooldown w opisie.\n\n[color=#f1bd79][b]Uważaj na uciekających przeciwników[/b][/color]\nWróg z kadłubem poniżej 10% ucieka wolniej, ale może zostawić minę. Nie leć bezmyślnie prosto za nim."], + ["Łup i wytwarzanie", "04", "[font_size=16][color=#f1bd79]Zbieraj. Porównuj. Twórz.[/color][/font_size]\n\n[color=#91dbea][b]Łup zbierasz przez podlecenie[/b][/color]\nPrzedmioty w pobliżu są przyciągane do statku. Magazyn mieści 20 przedmiotów; przy pełnym magazynie zwolnij miejsce, żeby zebrać kolejny.\n\n[color=#91dbea][b]Asteroidy zostawiają fizyczne odłamki[/b][/color]\nStrzelaj do asteroid. Po zniszczeniu rozpadają się bazowo na 5–7 poszarpanych fragmentów. Każdy to jedna jednostka surowca — musisz go zebrać. Umiejętność górnika zwiększa uzysk.\n\n[color=#91dbea][b]Przeszukuj wraki[/b][/color]\nPodleć do wraku i przytrzymaj E, aby go przeszukać. Wraki dają surowce (65%), amunicję lub rakiety (łącznie 20%) albo moduł (15%).\n\n[color=#91dbea][b]Warsztat fregaty — produkcja[/b][/color]\nZadokuj na fregacie i wybierz Warsztat. Tam wytworzysz amunicję, rakiety, części, powerbanki i wyposażenie kapitana. Koszt sprawdzisz w podpowiedzi przycisku produkcji.\n\n[color=#91dbea][b]Odzyskuj części[/b][/color]\nNajedź na zbędny przedmiot w magazynie i użyj przycisku rozłożenia. Części przydadzą się do napraw."], + ["Statek i kapitan", "05", "[font_size=16][color=#f1bd79]Buduj własny styl gry[/color][/font_size]\n\n[color=#91dbea][b]Wyposażenie[/b][/color]\nKliknij panel statku w prawym górnym rogu i otwórz magazyn. Przeciągaj przedmioty do pasujących slotów: maksymalnie 3 bronie, 5 modułów i 5 rozszerzeń. Na początku dostępny jest 1 slot broni i 1 rozszerzenia. Pierwszy dodatkowy slot broni kosztuje 100 tytanu, drugi 500. Rozszerzenia kosztują po 40 żelaza, aluminium i tytanu, a każdy kolejny slot podwaja ten koszt (80, 160, 320). Ładownia zaczyna z 5 miejscami; każde kolejne miejsce kosztuje 100 żelaza i 50 aluminium. Sloty odblokowujesz w hangarze fregaty. Po zbudowaniu składu modułów zakładka Magazyn na frachtowcu pozwala odkładać i odbierać wyposażenie. Aktywne rozszerzenia uruchamiasz klawiszami 1–5; pasywne (oznaczone P) działają automatycznie w tych samych slotach. Najedź kursorem, żeby sprawdzić parametry i porównanie wyposażenia.\n\n[color=#91dbea][b]Nie każdy duplikat jest taki sam[/b][/color]\nBroń i moduły mogą mieć różne parametry oraz addony. Aktywne rozszerzenia losują cooldown od 30 do 5 pełnych sekund. Pasywne mają losowaną siłę efektu: Recykler odnawia tarcze i energię po zebraniu odłamka, Wirus przejmuje uciekających wrogów, a Pancerz z tytanu ogranicza obrażenia przy niskim kadłubie. Krótsze odnowienia są rzadkie — przed rozłożeniem porównaj egzemplarze. Rozszerzenia tego samego typu dzielą aktywne odnowienie.\n\n[color=#91dbea][b]Umiejętności kapitana[/b][/color]\nZa pokonanych wrogów zdobywasz doświadczenie i kredyty. Trudniejsze układy dają więcej bazowego XP. Jeśli kapitan przewyższa poziom układu o ponad 2 poziomy, XP za przeciwników i ruiny maleje; przy przewadze 8 poziomów spada do zera. Kredyty i surowce nadal zbierasz. Po awansie wybierasz umiejętność. Pasywne działają stale, aktywne przypisujesz do F1–F5.\n\n[color=#f1bd79][b]Okno umiejętności nie pauzuje gry.[/b][/color]\nOtwieraj je w bezpiecznym miejscu. Przed kolejnym układem uzupełnij zapasy i sprawdź wyposażenie."] + ,["Planety i frachtowiec", "06", "[font_size=16][color=#f1bd79]Wyprawa na powierzchnię[/color][/font_size]\n\nPodleć do planety oznaczonej EARTHLIKE. [b]F[/b] skanuje tlen, temperaturę i zagrożenie biologiczne. [b]L[/b] rozpoczyna lądowanie. Możesz eksplorować przed pokonaniem wrogów, ale lądowanie jest zablokowane podczas walki.\n\nLądownik wymaga 100 HP przed startem i traci 5–20 HP przy wejściu w atmosferę. Na powierzchni sterujesz jak statkiem: [b]W[/b] — ciąg, [b]S[/b] — hamowanie i wstecz, [b]A/D[/b] — obrót, [b]Q/E[/b] — ruch boczny, [b]TAB[/b] — dopalanie. Odkrywaj miejsca i używaj [b]F[/b], aby je zbadać. Lądownik ma osobną energię dopalania. Każdy etap badania pokazuje szansę sukcesu; dalsze etapy dają więcej łupu i większe ryzyko.\n\n[b]L[/b] lub przycisk powrotu kończy wyprawę i przenosi łup do Twoich zasobów. Zniszczenie lądownika oznacza utratę tylko zdobyczy tej wyprawy. Kolejne lądowanie tworzy nową mapę.\n\n[color=#91dbea][b]Frachtowiec[/b][/color]\nZnajdziesz go przy gwieździe centralnej. Podleć i naciśnij [b]L[/b]. Hangar naprawia lądownik (1 część za 1% HP), warsztat prowadzi całą produkcję amunicji, rakiet, zaopatrzenia i sprzętu kapitana, a laboratorium przechowuje skany i archiwa.\n\nKapitan zaczyna z podstawowym systemem oddychania, skafandrem i bronią ręczną. Kolejne poziomy tworzysz w warsztacie; posiadany sprzęt zmienisz w Warsztacie. Kliknięcie panelu kapitana pokazuje sylwetkę, założone przedmioty i redukcję zagrożeń nad slotami. Wyższy poziom poprawia szanse eksploracji.\n\n[color=#91dbea][b]Losowe spotkania[/b][/color]\nPytajnik na mapie oznacza wydarzenie. Podleć, aby otworzyć okno. Miejscowy inżynier może zaoferować nieznany moduł za 100 kredytów. Wyższe poziomy przedmiotów są coraz rzadsze. Kupiony moduł pozostaje w ładowni wyprawy do bezpiecznego powrotu.\n\n[color=#f1bd79]Podczas wyprawy i wizyty we frachtowcu kosmos jest zamrożony. Zapisywanie między uruchomieniami gry nie jest jeszcze dostępne.[/color]"] +, ["Autorzy dźwięków", "07", "[font_size=16][color=#f1bd79]Dźwięki otoczenia[/color][/font_size]\n\n[b]Blender Foundation — Ambient Bird, Cricket and Frog (Yo Frankie!)[/b]\nOdgłosy świerszcza i żaby, udostępnione przez Lamoot:\nhttps://opengameart.org/content/ambient-bird-cricket-and-frog\nLicencja Creative Commons Attribution 3.0:\nhttps://creativecommons.org/licenses/by/3.0/\nZmiany: filtrowanie, płynne początki i zakończenia, zmiana wysokości żaby oraz konwersja do stereo 48 kHz. Autorzy nie są powiązani z tą grą.\n\n[b]Nagrania na licencji CC0[/b]\nThimras — Park ambiences (wiatr).\nIwan „qubodup” Gabovitch — 20 Rustles of dry leaves.\nisaiah658 — Ambient Bird Sounds.\nRudmer_Rotteveel — Wood Creak Single V7.\n\n[b]Wnętrze fregaty — CC0[/b]\nLEGIT Audio — The Shop (bezpłatne próbki OpenGameArt).\nbart — 68 Workshop Sounds i Steam release sounds.\nKenney — Sci-Fi Sounds.\n\nSzczegółowe źródła i zakres obróbki znajdują się w plikach CREDITS.md i manifest.json przy zasobach audio."] ] var _panel: PanelContainer var _reader: RichTextLabel @@ -20,27 +20,27 @@ func _ready() -> void: name = "PlayerGuide" set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) var dim := ColorRect.new() - dim.color = Color(0.005, 0.012, 0.025, 0.82) + dim.color = Color(0.005, 0.012, 0.025, 0.24) add_child(dim) dim.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) _panel = PanelContainer.new() var style := StyleBoxFlat.new() - style.bg_color = Color("0b1725") + style.bg_color = Color("0b17258a") style.border_color = Color("46798a") style.set_border_width_all(1) style.set_corner_radius_all(10) - style.set_content_margin_all(24) + style.set_content_margin_all(14) _panel.add_theme_stylebox_override("panel", style) add_child(_panel) var contents := VBoxContainer.new() - contents.add_theme_constant_override("separation", 18) + contents.add_theme_constant_override("separation", 10) _panel.add_child(contents) var header := HBoxContainer.new() contents.add_child(header) var heading := Label.new() heading.text = "INSTRUKCJA / AKADEMIA PILOTA" heading.size_flags_horizontal = Control.SIZE_EXPAND_FILL - heading.add_theme_font_size_override("font_size", 16) + heading.add_theme_font_size_override("font_size", 13) heading.add_theme_color_override("font_color", Color("91dbea")) header.add_child(heading) _close_button = Button.new() @@ -51,7 +51,7 @@ func _ready() -> void: contents.add_child(HSeparator.new()) var body := HBoxContainer.new() body.size_flags_vertical = Control.SIZE_EXPAND_FILL - body.add_theme_constant_override("separation", 24) + body.add_theme_constant_override("separation", 12) contents.add_child(body) var navigation := VBoxContainer.new() navigation.custom_minimum_size.x = 190 @@ -61,10 +61,10 @@ func _ready() -> void: var button := Button.new() button.text = "%s %s" % [PAGES[index][1], PAGES[index][0]] button.alignment = HORIZONTAL_ALIGNMENT_LEFT - button.custom_minimum_size.y = 44 + button.custom_minimum_size.y = 32 BUTTON_STYLE.apply(button) button.add_theme_font_override("font", ThemeDB.fallback_font) - button.add_theme_font_size_override("font_size", 14) + button.add_theme_font_size_override("font_size", 11) button.pressed.connect(_show_page.bind(index)) navigation.add_child(button) _tabs.append(button) @@ -76,7 +76,7 @@ func _ready() -> void: _reader.size_flags_vertical = Control.SIZE_EXPAND_FILL _reader.add_theme_font_override("normal_font", ThemeDB.fallback_font) _reader.add_theme_font_override("bold_font", ThemeDB.fallback_font) - _reader.add_theme_font_size_override("normal_font_size", 17) + _reader.add_theme_font_size_override("normal_font_size", 13) _reader.add_theme_constant_override("line_separation", 5) _reader.add_theme_color_override("default_color", Color("c5d4df")) body.add_child(_reader) diff --git a/scripts/ui/ship_inventory_panel.gd b/scripts/ui/ship_inventory_panel.gd index 4cd8462..8c844ec 100644 --- a/scripts/ui/ship_inventory_panel.gd +++ b/scripts/ui/ship_inventory_panel.gd @@ -52,7 +52,7 @@ func _create_resource_section() -> void: var frame := PanelContainer.new() frame.name = "ResourceSection" var style := StyleBoxFlat.new() - style.bg_color = Color("101e2d") + style.bg_color = Color("101e2d47") style.border_color = Color("2d4c60") style.set_border_width_all(1) style.set_corner_radius_all(5) diff --git a/scripts/ui/ship_profile.gd b/scripts/ui/ship_profile.gd index 7c4e9d1..6d56eba 100644 --- a/scripts/ui/ship_profile.gd +++ b/scripts/ui/ship_profile.gd @@ -1,9 +1,12 @@ extends Button -const FONT := preload("res://assets/fonts/font2.ttf") var player: CharacterBody2D var _texture: Texture2D -var _ship_name := "" +var _frame_texture: Texture2D +var _frame_region := Rect2() +var _display := Vector3.ONE +const TEXT := Color("dce8e7") +const MUTED := Color("88a7ae") func _ready() -> void: focus_mode = Control.FOCUS_NONE @@ -11,46 +14,54 @@ func _ready() -> void: for state in ["normal", "hover", "pressed", "focus"]: add_theme_stylebox_override(state, StyleBoxEmpty.new()) var ship := ShipCatalog.for_path(GameState.selected_ship_path) - _ship_name = ship["name"] _texture = load(ShipCatalog.texture_path(ship)) as Texture2D + _display = _ratios() + _frame_texture = load("res://assets/ui/frames/ship_ring_bars.png") as Texture2D + _frame_region = Rect2(Vector2.ZERO, _frame_texture.get_size()) -func _process(_delta: float) -> void: +func _ratios() -> Vector3: + if not is_instance_valid(player): return Vector3.ZERO + return Vector3(player.hull / maxf(1, player.max_hull), player.shields / maxf(1, player.max_shields), player.energy / maxf(1, player.max_energy)).clamp(Vector3.ZERO, Vector3.ONE) + +func _process(delta: float) -> void: + _display = _display.lerp(_ratios(), 1.0 - exp(-delta * 12.0)) queue_redraw() func _draw() -> void: - if not is_instance_valid(player): - return - var portrait_center := Vector2(size.x - 54, 55) - var color := Color("91dbea") if is_hovered() else Color("376779") - var style := StyleBoxFlat.new() - style.bg_color = Color("091522f5") - style.border_color = color - style.set_border_width_all(1) - style.set_corner_radius_all(12) - draw_style_box(style, Rect2(0, 9, size.x - 48, 94)) - draw_circle(portrait_center, 50, Color("0a1725")) - draw_arc(portrait_center, 50, 0, TAU, 64, color, 3, true) - draw_arc(portrait_center, 44, 0, TAU, 64, Color("efb568"), 1, true) + if not is_instance_valid(player): return + var portrait := Vector2(185, 35.5) + draw_circle(portrait, 26, Color("0a141b66")) if _texture != null: var dimensions := _texture.get_size() - var display_size := dimensions * (70.0 / maxf(dimensions.x, dimensions.y)) - draw_texture_rect(_texture, Rect2(portrait_center - display_size * 0.5, display_size), false) - draw_string(FONT, Vector2(14, 29), _ship_name.to_upper(), HORIZONTAL_ALIGNMENT_LEFT, size.x - 120, 13, Color("c9e8ff")) - _bar(Rect2(12, 38, size.x - 118, 24), float(player.get("hull")), float(player.get("max_hull")), Color("df7158"), "KADŁUB") - _bar(Rect2(12, 68, size.x - 118, 24), float(player.get("shields")), float(player.get("max_shields")), Color("478ddd"), "TARCZE") + var extent := dimensions * (44.0 / maxf(dimensions.x, dimensions.y)) + draw_texture_rect(_texture, Rect2(portrait - extent * 0.5, extent), false) + _bar(Rect2(12, 15, 126, 7), player.hull, player.max_hull, _display.x, Color("e88972"), "KADŁUB") + _bar(Rect2(12, 32, 126, 7), player.shields, player.max_shields, _display.y, Color("79bde5"), "TARCZE") + _bar(Rect2(12, 49, 126, 7), player.energy, player.max_energy, _display.z, Color("87cfb1"), "ENERGIA") + if _frame_texture != null: + draw_texture_rect_region(_frame_texture, Rect2(Vector2.ZERO, size), _frame_region, Color(1, 1, 1, 1.0 if is_hovered() else 0.88)) + _bar_caption(Vector2(13, 21), player.hull, player.max_hull, "KADŁUB") + _bar_caption(Vector2(13, 38), player.shields, player.max_shields, "TARCZE") + _bar_caption(Vector2(13, 55), player.energy, player.max_energy, "ENERGIA") -func _bar(rect: Rect2, value: float, maximum: float, color: Color, caption: String) -> void: - var background := StyleBoxFlat.new() - background.bg_color = Color("060e18") - background.border_color = color.darkened(0.4) - background.set_border_width_all(1) - background.set_corner_radius_all(7) - draw_style_box(background, rect) - var fill_rect := rect.grow(-3) - fill_rect.size.x *= clampf(value / maxf(1.0, maximum), 0.0, 1.0) - if fill_rect.size.x > 0: - var fill := StyleBoxFlat.new() - fill.bg_color = color - fill.set_corner_radius_all(4) - draw_style_box(fill, fill_rect) - draw_string(FONT, rect.position + Vector2(0, 16), "%s %.0f / %.0f" % [caption, value, maximum], HORIZONTAL_ALIGNMENT_CENTER, rect.size.x, 10, Color.WHITE) +func _bar_caption(point: Vector2, value: float, maximum: float, caption: String) -> void: + var font := ThemeDB.fallback_font + var values := "%.0f / %.0f" % [value, maximum] + draw_string_outline(font, point, caption, HORIZONTAL_ALIGNMENT_LEFT, 58, 7, 2, Color("071117")) + draw_string_outline(font, point, values, HORIZONTAL_ALIGNMENT_RIGHT, 123, 7, 2, Color("071117")) + draw_string(font, point, caption, HORIZONTAL_ALIGNMENT_LEFT, 58, 7, TEXT) + draw_string(font, point, values, HORIZONTAL_ALIGNMENT_RIGHT, 123, 7, TEXT) + +func _bar(rect: Rect2, value: float, maximum: float, ratio: float, color: Color, _caption: String) -> void: + var track := StyleBoxFlat.new() + track.bg_color = Color("071117") + track.set_corner_radius_all(2) + draw_style_box(track, rect) + var fill := track.duplicate() as StyleBoxFlat + fill.bg_color = color + if ratio > 0.001: + draw_style_box(fill, Rect2(rect.position, Vector2(rect.size.x * ratio, rect.size.y))) + draw_line(rect.position + Vector2(1, 1), rect.position + Vector2(maxf(1, rect.size.x * ratio - 1), 1), Color(color.lightened(0.3), 0.6), 1) + for i in range(1, 10): + var x := rect.position.x + rect.size.x * float(i) / 10.0 + draw_line(Vector2(x, rect.position.y), Vector2(x, rect.end.y), Color("101d2466"), 1) diff --git a/scripts/ui/ship_selection.gd b/scripts/ui/ship_selection.gd index 8f7137a..cee48a5 100644 --- a/scripts/ui/ship_selection.gd +++ b/scripts/ui/ship_selection.gd @@ -16,6 +16,7 @@ func _ready() -> void: func _frame(accent: Color, highlighted: bool) -> StyleBoxFlat: var style := StyleBoxFlat.new() style.bg_color = Color("142b42") if highlighted else Color("0b192a") + style.bg_color.a = 0.48 style.border_color = accent if highlighted else Color("29435a") style.set_border_width_all(2 if highlighted else 1) style.set_corner_radius_all(10) @@ -27,7 +28,7 @@ func _label(text: String, font_size: int, color: Color) -> Label: var label := Label.new() label.text = text label.mouse_filter = Control.MOUSE_FILTER_IGNORE - label.add_theme_font_size_override("font_size", font_size) + label.add_theme_font_size_override("font_size", clampi(font_size, 10, 14)) label.add_theme_color_override("font_color", color) return label diff --git a/scripts/ui/ship_statistics.gd b/scripts/ui/ship_statistics.gd new file mode 100644 index 0000000..faa1d7b --- /dev/null +++ b/scripts/ui/ship_statistics.gd @@ -0,0 +1,246 @@ +extends PanelContainer +const UI := preload("res://scripts/planets/freighter_menu.gd") +const DEFENSE := Color("e9a08a") +const ENERGY := Color("89d2b2") +const CYAN := Color("83c7e6") +const GOLD := Color("dfb775") +var player: CharacterBody2D +var inventory: ShipInventory +var _body: VBoxContainer +var _grid: GridContainer +var _header: HBoxContainer +var _subtitle: Label +var _tabs: Dictionary = {} +var _bindings: Dictionary = {} +var _tab := "parameters" +var _elapsed := 0.0 + +func _ready() -> void: + name = "ShipStatistics" + UI.style(self, 12, 0.48) + var frame := preload("res://scripts/ui/ornamental_frame.gd").new() + frame.corner_size = 18 + frame.opacity = 0.75 + add_child(frame) + var stack := VBoxContainer.new() + stack.add_theme_constant_override("separation", 5) + add_child(stack) + _header = UI.row(stack) + var title := UI.label(_header, "STATYSTYKI STATKU", 17, GOLD) + title.size_flags_horizontal = Control.SIZE_EXPAND_FILL + title.autowrap_mode = TextServer.AUTOWRAP_OFF + title.mouse_filter = Control.MOUSE_FILTER_IGNORE + UI.button(_header, "×", hide).custom_minimum_size.x = 32 + _subtitle = UI.label(stack, "", 11, UI.MUTED) + _subtitle.autowrap_mode = TextServer.AUTOWRAP_OFF + var navigation := UI.row(stack) + for entry in [["parameters", "PARAMETRY"], ["weapons", "UZBROJENIE"], ["equipment", "SYSTEMY I MODUŁY"]]: + var button := UI.button(navigation, entry[1], _select_tab.bind(entry[0])) + button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + button.custom_minimum_size.y = 26 + button.add_theme_font_size_override("font_size", 10) + _tabs[entry[0]] = button + var scroll := ScrollContainer.new() + scroll.name = "StatisticsScroll" + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + stack.add_child(scroll) + _body = VBoxContainer.new() + _body.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _body.add_theme_constant_override("separation", 8) + scroll.add_child(_body) + inventory.inventory_changed.connect(_equipment_changed) + get_viewport().size_changed.connect(_layout) + _layout() + hide() + +func open() -> void: + _rebuild() + _layout() + show() + get_parent().get_node("FloatingWindows").focus_window(self) + +func _layout() -> void: + var viewport_size := get_viewport_rect().size + size = Vector2(minf(690, viewport_size.x - 32), minf(490, viewport_size.y - 48)) + if not has_meta("floating_window_dragged"): + position = (viewport_size - size) * 0.5 + else: + get_parent().get_node("FloatingWindows").clamp_window(self) + if is_instance_valid(_grid): _grid.columns = 2 if size.x >= 600 else 1 + +func _select_tab(tab: String) -> void: + _tab = tab + _rebuild() + _body.get_parent().scroll_vertical = 0 + +func _equipment_changed() -> void: + if visible: _rebuild.call_deferred() + +func _process(delta: float) -> void: + if not visible: return + _layout() + _elapsed += delta + if _elapsed >= 0.2: + _elapsed = 0 + _refresh_values() + +func _unhandled_key_input(event: InputEvent) -> void: + if visible and event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE: + hide() + get_viewport().set_input_as_handled() + +func _rebuild() -> void: + _bindings.clear() + for child in _body.get_children(): + _body.remove_child(child) + child.queue_free() + for tab in _tabs: + _tabs[tab].modulate = GOLD if tab == _tab else Color.WHITE + _grid = GridContainer.new() + _grid.columns = 2 if size.x >= 640 else 1 + _grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _grid.add_theme_constant_override("h_separation", 6) + _grid.add_theme_constant_override("v_separation", 6) + _body.add_child(_grid) + match _tab: + "parameters": _parameters() + "weapons": _weapons() + "equipment": _equipment() + _refresh_values() + _layout.call_deferred() + +func _section(title: String, color: Color) -> VBoxContainer: + var card := UI.card(_grid) + card.get_parent().size_flags_horizontal = Control.SIZE_EXPAND_FILL + card.get_parent().custom_minimum_size.x = 260 + UI.style(card.get_parent(), 6, 0.24) + card.add_theme_constant_override("separation", 1) + var heading := UI.row(card) + heading.add_theme_constant_override("separation", 5) + var icon_path := "res://assets/icons/computer.png" + if title.begins_with("01"): icon_path = "res://assets/freighter/research/hull.png" + elif title.begins_with("02"): icon_path = "res://assets/freighter/research/shields.png" + elif title.begins_with("03") or title.begins_with("BROŃ"): icon_path = "res://assets/freighter/research/weapons.png" + elif title.begins_with("04"): icon_path = "res://assets/icons/engine.png" + elif title.begins_with("05"): icon_path = "res://assets/icons/cargo_crate.svg" + elif title.begins_with("06"): icon_path = "res://assets/freighter/research/general.png" + UI.icon(heading,load(icon_path),16).mouse_filter = Control.MOUSE_FILTER_IGNORE + UI.label(heading, title, 12, color).autowrap_mode = TextServer.AUTOWRAP_OFF + var line := HSeparator.new() + line.modulate = Color(color, 0.3) + card.add_child(line) + return card + +func _metric(card: VBoxContainer, key: String, caption: String, read_value: Callable, color := CYAN, hint := "") -> void: + var row := UI.row(card) + row.tooltip_text = hint + var label := UI.label(row, caption, 12, UI.MUTED) + label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + label.autowrap_mode = TextServer.AUTOWRAP_OFF + label.mouse_filter = Control.MOUSE_FILTER_IGNORE + var value := UI.label(row, "", 12, color) + value.autowrap_mode = TextServer.AUTOWRAP_OFF + value.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + value.mouse_filter = Control.MOUSE_FILTER_IGNORE + _bindings[key] = {"label":value, "read":read_value} + +func _refresh_values() -> void: + if not is_instance_valid(player): return + var ship := ShipCatalog.for_path(GameState.selected_ship_path) + _subtitle.text = "%s / System %d / %s / DPS %.1f" % [ship.name, GameState.system_level, "HARD" if GameState.system_level > 60 else "NORMALNY", inventory.get_total_dps()] + for entry in _bindings.values(): + entry.label.text = str(entry.read.call()) + +func _parameters() -> void: + var card := _section("01 / PANCERZ I OCHRONA", DEFENSE) + _metric(card, "hull", "Kadłub", func(): return "%.0f / %.0f" % [player.hull,player.max_hull], DEFENSE) + _metric(card, "reduction", "Redukcja obrażeń", func(): return "%.1f%%" % (player.get_damage_reduction()*100), DEFENSE, "Uwzględnia mechanika i aktywny efekt pancerza z tytanu.") + _metric(card, "evasion", "Szansa na unik", func(): return "%.1f%%" % (player.get_evasion_chance()*100), DEFENSE) + for index in range(3): + _metric(card, DamageTypes.KEYS[index], "Absorpcja: " + DamageTypes.NAMES[index].to_lower(), func(): return "%.1f%%" % player.absorption[index], DEFENSE) + card = _section("02 / TARCZE I ENERGIA", ENERGY) + _metric(card, "shields", "Tarcze", func(): return "%.0f / %.0f" % [player.shields,player.max_shields], CYAN) + _metric(card, "shield_regeneration", "Regeneracja tarcz", func(): return "%.1f / s" % player.shield_regeneration, CYAN) + _metric(card, "shield_on_damage", "Odzysk tarcz z obrażeń", func(): return "%.1f%%" % player.shield_on_damage_percent, CYAN) + _metric(card, "energy", "Energia", func(): return "%.0f / %.0f" % [player.energy,player.max_energy], ENERGY) + _metric(card, "energy_regeneration", "Regeneracja energii", func(): return "%.1f / s" % player.get_energy_regeneration(), ENERGY, "Aktualna regeneracja, także ładowanie przy gwieździe i premie kapitana.") + _metric(card, "solar", "Ładowanie słoneczne", func(): return "%.1f / s" % player.get_solar_regeneration(), ENERGY) + card = _section("03 / SIŁA OGNIA", GOLD) + _metric(card, "dps", "Łączny DPS", func(): return "%.1f" % inventory.get_total_dps(), GOLD, "Teoretyczny DPS: uwzględnia krytyki i promieniowanie; przed obroną celu, przy dostępnej energii i amunicji.") + _metric(card, "damage", "Premia do obrażeń", func(): return "%+.1f%%" % ((player.get_weapon_damage_multiplier()-1)*100), GOLD) + _metric(card, "critical", "Szansa na krytyk", func(): return "%.1f%%" % (player.get_critical_chance()*100), GOLD) + _metric(card, "critical_damage", "Mnożnik krytyka", func(): return "×%.2f" % player.get_critical_multiplier(), GOLD) + card = _section("04 / NAPĘD I NAWIGACJA", CYAN) + _metric(card, "speed", "Prędkość aktualna", func(): return "%.0f px/s" % player.velocity.length()) + _metric(card, "max_speed", "Prędkość maksymalna", func(): return "%.0f px/s" % player.max_speed) + _metric(card, "acceleration", "Przyspieszenie", func(): return "%.0f px/s²" % player.thrust_acceleration) + _metric(card, "rotation", "Prędkość obrotu", func(): return "%.0f °/s" % rad_to_deg(player.max_turn_speed)) + _metric(card, "scanner", "Zasięg skanera", func(): return "%.0f px" % player.scanner_range) + card = _section("05 / ŁADOWNIA I ZAOPATRZENIE", GOLD) + _metric(card, "cargo", "Zajęte miejsca", func(): return "%d / %d" % [inventory.get_cargo_used(),inventory.get_cargo_capacity()], GOLD) + _metric(card, "ammunition", "Amunicja zwykła", func(): return str(inventory.ammunition), GOLD) + _metric(card, "gamma", "Amunicja radiacyjna", func(): return str(inventory.irradiated_ammunition), GOLD) + _metric(card, "missiles", "Rakiety", func(): return str(inventory.missile_ammunition), GOLD) + _metric(card, "banks", "Banki energii", func(): return str(inventory.energy_banks), ENERGY) + card = _section("06 / PREMIE I BADANIA", Color("b6a0d7")) + _metric(card, "xp", "Premia do doświadczenia", func(): return "%+.1f%%" % ((player.experience_multiplier-1)*100), GOLD) + _metric(card, "credits", "Premia do kredytów", func(): return "%+.1f%%" % ((player.credits_multiplier-1)*100), GOLD) + _metric(card, "luck", "Szansa szczęścia", func(): return "%.1f%%" % (player.get_luck_chance()*100), GOLD) + var research := preload("res://scripts/planets/alien_research.gd") + for branch in research.BRANCHES: + _metric(card, "research_" + branch, {"weapons":"Osłabienie broni obcych","hull":"Obrażenia kadłubów obcych","shields":"Obrażenia tarcz obcych"}[branch], func(): return "%.0f%%" % (research.bonus(GameState.captain.expedition,branch)*100), ENERGY) + +func _weapons() -> void: + for index in range(inventory.WEAPON_SLOT_COUNT): + var card := _section("BROŃ %d / %s" % [index+1,["LPM","PPM","ŚPM"][index]], GOLD) + if not inventory.is_slot_unlocked("weapon",index): + UI.label(card, "Slot zablokowany • Odblokuj w hangarze", 12, UI.MUTED) + continue + var item := inventory.get_item("weapon", index) + if item == null: + UI.label(card, "Brak zamontowanej broni", 13, UI.MUTED) + continue + _item_header(card,item) + _metric(card, "weapon_dps_%d" % index, "DPS", func(): return "%.1f" % inventory.get_weapon_dps(index), GOLD) + _metric(card, "weapon_damage_%d" % index, "Obrażenia trafienia", func(): return "%.1f – %.1f" % [item.get_damage_range().x*player.get_weapon_damage_multiplier(), item.get_damage_range().y*player.get_weapon_damage_multiplier()], GOLD, "Zakres przed krytykiem i obroną przeciwnika.") + _metric(card, "weapon_interval_%d" % index, "Odstęp między strzałami", func(): return "%.2f s" % (inventory.get_missile_cooldown(item) if item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE else item.definition.fire_interval)) + _metric(card, "weapon_energy_%d" % index, "Energia na strzał", func(): return "%.1f" % item.get_energy_cost(), ENERGY) + _metric(card, "weapon_range_%d" % index, "Zasięg", func(): return "%.0f px" % item.definition.weapon_range) + UI.label(card,"Typ: " + DamageTypes.NAMES[item.definition.get_damage_type()],12,UI.MUTED) + var info := _section("ODCZYT PARAMETRÓW", CYAN) + UI.label(info,"DPS uwzględnia premie wyposażenia, kapitana, krytyki i promieniowanie. To wartość teoretyczna, przed obroną celu; rzeczywisty wynik zależy od trafień, energii i amunicji.",13,UI.MUTED) + UI.label(info,"Najedź na nazwę przedmiotu, aby zobaczyć wszystkie addony i parametry.",13,UI.MUTED) + +func _item_header(card: VBoxContainer, item: ItemInstance) -> void: + var row := UI.row(card) + row.tooltip_text = item.get_tooltip_text() + UI.icon(row,item.definition.icon,24).mouse_filter = Control.MOUSE_FILTER_IGNORE + var label := UI.label(row,"%s • poz. %d" % [item.definition.display_name,item.item_level],12,item.get_type_color()) + label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + label.mouse_filter = Control.MOUSE_FILTER_IGNORE + +func _equipment() -> void: + var card := _section("MODUŁY STATKU", CYAN) + for index in range(inventory.MODULE_SLOT_COUNT): + UI.label(card,inventory.MODULE_NAMES[index].to_upper(),12,CYAN) + var item := inventory.get_item("module",index) + if item == null: UI.label(card,"Brak modułu",13,UI.MUTED) + else: + _item_header(card,item) + UI.label(card,"%s: %.1f %s" % [ItemInstance.stat_name(item.definition.primary_stat), item.get_stat_total(item.definition.primary_stat),item.definition.stat_suffix],12,UI.MUTED) + card = _section("ROZSZERZENIA", ENERGY) + for index in range(inventory.EXTENSION_SLOT_COUNT): + UI.label(card,"SLOT %d" % (index+1),12,ENERGY) + if not inventory.is_slot_unlocked("extension",index): + UI.label(card,"Zablokowany",13,UI.MUTED) + continue + var item := inventory.get_item("extension",index) + if item == null: + UI.label(card,"Brak rozszerzenia",13,UI.MUTED) + continue + _item_header(card,item) + if item.is_passive_extension(): UI.label(card,item.get_passive_description(),13,UI.MUTED) + else: + UI.label(card, "Odnowienie: %.0f s" % item.get_active_ability().cooldown, 13, UI.MUTED) + _metric(card,"extension_%d" % index,"Pozostało",func(): return "%.1f s" % player.get_ability_cooldown(index),ENERGY) diff --git a/scripts/ui/ship_statistics.gd.uid b/scripts/ui/ship_statistics.gd.uid new file mode 100644 index 0000000..71cb8dd --- /dev/null +++ b/scripts/ui/ship_statistics.gd.uid @@ -0,0 +1 @@ +uid://dk8a1d5q0v5id diff --git a/tests/items/weapon_comparison_test.gd b/tests/items/weapon_comparison_test.gd index df6bc95..5e02074 100644 --- a/tests/items/weapon_comparison_test.gd +++ b/tests/items/weapon_comparison_test.gd @@ -34,6 +34,7 @@ func _ready() -> void: for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) var inventory: ShipInventory = ship.get_node("ShipInventory") + inventory.unlocked_weapon_slots = 3 var old_first := weapon(10) var old_second := weapon(20) inventory.weapon_slots.assign([old_first, old_second, null]) diff --git a/tests/levels/enemy_repair_notification_test.gd b/tests/levels/enemy_repair_notification_test.gd index 344acca..c2af6fc 100644 --- a/tests/levels/enemy_repair_notification_test.gd +++ b/tests/levels/enemy_repair_notification_test.gd @@ -20,6 +20,14 @@ func _ready() -> void: enemy.hull = 0.0 enemy.regenerate_defenses(10.0) assert(enemy.hull == 0.0) + enemy.loot_tier = 2 + enemy.hull = 25.0 + enemy.shields = 40.0 + enemy.regenerate_defenses(1000.0) + assert(enemy.hull == 25.0 and enemy.shields == 40.0) + enemy.loot_tier = 1 + enemy.regenerate_defenses(1.0) + assert(enemy.hull == 26.0 and enemy.shields == 42.0) var button := Button.new() button.set_script(preload("res://scripts/ui/navigation_button.gd")) button.configure_navigation(null, Color("b9a0ef"), "KAPITAN") @@ -32,5 +40,5 @@ func _ready() -> void: GameState.captain.learning_points = 0 button._process(0.1) assert((button.get_theme_stylebox("normal") as StyleBoxFlat).shadow_size == original) - print("ENEMY_REPAIR_NOTIFICATION_TEST: PASS 1%/s, retreat threshold, caps, dead enemy, notification reset") + print("ENEMY_REPAIR_NOTIFICATION_TEST: PASS 1%/s, retreat threshold, caps, dead enemy, boss regeneration disabled, elite regeneration, notification reset") get_tree().quit() diff --git a/tests/levels/hard_balance_test.gd b/tests/levels/hard_balance_test.gd new file mode 100644 index 0000000..bf4a2a6 --- /dev/null +++ b/tests/levels/hard_balance_test.gd @@ -0,0 +1,64 @@ +extends Node +const BALANCE := preload("res://scripts/levels/level_balance.gd") +const ENEMY := preload("res://scenes/game/enemy_ship.tscn") + +func _ready() -> void: + GameState.start_new_run() + assert(BALANCE.MAX_LEVEL == 120) + assert(not BALANCE.is_hard(60) and BALANCE.is_hard(61)) + var previous := 0.0 + for level in range(1, 121): + var total := BALANCE.enemy_absorption_total(level) + assert(total >= previous and total <= (30.0 if level <= 60 else 60.0)) + for seed_value in [1, 12345, 9876]: + var profile := DamageTypes.enemy_profile(level, seed_value) + var values: Vector3 = profile.absorption + assert(is_equal_approx(values.x + values.y + values.z, total)) + assert(values.x >= 0 and values.y >= 0 and values.z >= 0) + previous = total + assert(is_equal_approx(BALANCE.enemy_absorption_total(60), 30.0)) + assert(is_equal_approx(BALANCE.enemy_absorption_total(120), 60.0)) + assert(is_equal_approx(BALANCE.enemy_absorption_total(1000), 60.0)) + var enemy := ENEMY.instantiate() as CharacterBody2D + add_child(enemy) + enemy.set_physics_process(false) + for level in [1, 3, 6, 30, 60, 61, 90, 120]: + var base_power: float = 1.0 + 0.05 * (level - 1) + var mode_factor := 2.0 if level > 60 else 1.0 + for tier in range(3): + enemy.apply_level_settings(level, tier) + var combat := 2.0 if tier == 2 else 1.25 + var hull_factor := 4.0 if tier == 2 else (2.0 if tier == 1 else 1.0) + var damage_factor := 4.0 if tier == 2 else (1.3 if tier == 1 else 1.0) + var old_hull: float = 50.0 * base_power * hull_factor * combat + var old_damage: float = 8.0 * base_power * damage_factor * combat + if tier == 2: + var intro := clampf(float(level - 1) / 5.0, 0.0, 1.0) + old_hull *= lerpf(0.6, 1.0, intro) + old_damage *= lerpf(0.5, 1.0, intro) + assert(is_equal_approx(enemy.max_hull, old_hull * mode_factor * (5.0 if tier == 2 else 1.0))) + assert(is_equal_approx(enemy.max_shields, old_hull * 0.4 * mode_factor * (3.0 if tier == 2 else 1.0))) + assert(is_equal_approx(enemy.weapon_damage, old_damage * mode_factor * (0.5 if tier == 2 else 1.0) * (0.25 if tier == 2 and level == 1 else 1.0))) + assert(is_equal_approx(enemy.hull, enemy.max_hull) and is_equal_approx(enemy.shields, enemy.max_shields)) + enemy.apply_level_settings(1, 2) + assert(is_equal_approx(enemy.weapon_damage, 4.0)) + assert(is_equal_approx(enemy.weapon_cooldown, 1.875)) + enemy.apply_level_settings(2, 2) + assert(enemy.weapon_damage > 4.0 and enemy.weapon_cooldown < 1.0) + enemy.free() + for level in [60, 61, 120]: + GameState.system_level = level + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + game.system_cleared = true + game.player.global_position = game.protected_planet.global_position + game.services_menu.show_services(level == 120) + assert(GameState.system_level == level) + if level == 60: assert(game.services_menu.next_button.text == "PRZEJDŹ DO HARD") + assert(game.services_menu.next_button.disabled == (level == 120)) + assert(game.open_wormhole() == (level < 120)) + game.free() + print("HARD_BALANCE_TEST_OK: levels 1-120, 60/61 transition, absorption, all tiers, boss multipliers and intro") + get_tree().quit() diff --git a/tests/levels/hard_balance_test.gd.uid b/tests/levels/hard_balance_test.gd.uid new file mode 100644 index 0000000..236d26d --- /dev/null +++ b/tests/levels/hard_balance_test.gd.uid @@ -0,0 +1 @@ +uid://lcx0uvbmerj3 diff --git a/tests/levels/hard_balance_test.tscn b/tests/levels/hard_balance_test.tscn new file mode 100644 index 0000000..4aee6df --- /dev/null +++ b/tests/levels/hard_balance_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/levels/hard_balance_test.gd" id="1"] +[node name="HardBalanceTest" type="Node"] +script = ExtResource("1") diff --git a/tests/levels/surface_poi_counts_test.gd b/tests/levels/surface_poi_counts_test.gd index 38764d7..5db401f 100644 --- a/tests/levels/surface_poi_counts_test.gd +++ b/tests/levels/surface_poi_counts_test.gd @@ -4,6 +4,7 @@ const SCENERY := preload("res://scripts/planets/surface_scenery.gd") func _ready() -> void: var extra_ruins := 0 + var observed_totals := {} for index in 64: var profile: Dictionary = preload("res://scripts/planets/planet_profiles.gd").generate(711,index,"Test") var data: Dictionary = GENERATOR.generate(500+index,profile) @@ -12,12 +13,15 @@ func _ready() -> void: for poi in data.pois: if poi.kind != "cave": continue assert(poi.has("mountain_position")) - assert(poi.position.distance_to(poi.mountain_position) == 86) + assert(is_equal_approx(poi.position.distance_to(poi.mountain_position), 86.0)) assert(data.mountains.any(func(m): return m.get("cave_anchor",false) and m.position == poi.mountain_position)) for other in data.pois: if other.id != poi.id: assert(other.position.distance_to(poi.position) >= 420) - assert(counts.warehouse == 1 and counts.village == 1 and counts.cave == 1 and counts.ruins in [1,2]) - assert(counts.deposit == 2) + assert(counts.warehouse == 1 and counts.village == 1 and counts.ruins in [1,2]) + assert(counts.deposit >= 2 and counts.cave >= 2) + var natural_count: int = counts.deposit + counts.cave + assert(natural_count >= 5 and natural_count <= 10) + observed_totals[natural_count] = true assert(data.events.size() == 1 and data.events[0].position.is_finite()) assert(data.events[0].position.length() > 300) extra_ruins += int(counts.ruins == 2) @@ -26,6 +30,7 @@ func _ready() -> void: assert(repeated.pois == data.pois and repeated.events == data.events) # Most maps have one of each, with some maps containing a second. assert(extra_ruins > 4 and extra_ruins < 30) + assert(observed_totals.size() == 6) # No flat ground can disable the guaranteed question-mark event. var fallback := {"seed":987,"heights":PackedFloat32Array(),"trees":[],"rocks":[],"mountains":[],"pois":[]} fallback.heights.resize(96*96) @@ -35,5 +40,5 @@ func _ready() -> void: SCENERY.generate(fallback,rng) assert(fallback.events.size() == 1 and fallback.events[0].position.is_finite()) assert(fallback.events[0].position.length() > 400) - print("SURFACE POI COUNTS PASS: 64 maps, ruins 1..2, two deposits, warehouse/village/cave once, one guaranteed event, deterministic layout; extra ruins=",extra_ruins) + print("SURFACE POI COUNTS PASS: 64 maps, ruins 1..2, 5..10 caves/deposits combined, both kinds at least twice, warehouse/village once, one guaranteed event, deterministic layout; extra ruins=",extra_ruins) get_tree().quit() diff --git a/tests/levels/system_generation_test.gd b/tests/levels/system_generation_test.gd index db5c16c..c570f1b 100644 --- a/tests/levels/system_generation_test.gd +++ b/tests/levels/system_generation_test.gd @@ -17,7 +17,7 @@ func _ready() -> void: for point in BALANCE.COUNT_POINTS: assert(BALANCE.enemy_count(int(point.x)) == int(point.y)) var previous_count := 0 - for level in range(1, 1001): + for level in range(1, BALANCE.MAX_LEVEL + 1): var count := BALANCE.enemy_count(level) assert(count >= previous_count and count <= 40) assert(BALANCE.enemy_tiers(level).size() == count) @@ -25,7 +25,7 @@ func _ready() -> void: previous_count = count var observed_counts: Dictionary = {} var observed_ship_types: Dictionary = {} - for level in [1, 10, 50, 100, 250, 500, 1000]: + for level in [1, 10, 50, 60, 61, 100, 120]: for seed_value in range(1, 61): var data := GENERATOR.generate(level, seed_value) var ship_type: int = data["enemy_texture_index"] @@ -63,4 +63,4 @@ func _ready() -> void: assert(enemies[index]["tier"] == BALANCE.enemy_tiers(level)[index]) assert(observed_counts.size() == 5) assert(observed_ship_types.size() == GENERATOR.ALIEN_SHIPS.TEXTURES.size()) - print("SYSTEM_GENERATION_TEST: PASS (420 layouts, deterministic retries, planets, safe spawn and level balance 1–1000)") + print("SYSTEM_GENERATION_TEST: PASS (420 layouts, deterministic retries, planets, safe spawn and level balance 1–120)") diff --git a/tests/previews/cockpit_console_review.gd b/tests/previews/cockpit_console_review.gd new file mode 100644 index 0000000..67582cd --- /dev/null +++ b/tests/previews/cockpit_console_review.gd @@ -0,0 +1,50 @@ +extends Node + +func settle() -> void: + for frame in 12: await get_tree().process_frame + +func _ready() -> void: + GameState.start_new_run() + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + game.player.get_node("WeaponController").set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): + enemy.set_physics_process(false) + enemy.apply_level_settings(120, 2) + enemy.max_shields = 999999 + enemy.shields = 999999 + var hud := game.get_node("HUD") + var cockpit = hud._cockpit + cockpit._inventory.ammunition = 999999 + cockpit._inventory.irradiated_ammunition = 999999 + cockpit._inventory.missile_ammunition = 999999 + game.player.absorption = Vector3(20, 20, 20) + for resolution in [Vector2i(1280, 720), Vector2i(960, 540), Vector2i(800, 600)]: + get_window().size = resolution + await settle() + hud._layout_sidebar() + await settle() + var rect: Rect2 = cockpit.get_global_rect() + assert(rect.position.x >= 0 and rect.position.y >= 0) + assert(rect.end.x <= hud.get_node("HUDRoot").size.x + 1) + assert(rect.end.y <= hud.get_node("HUDRoot").size.y + 1) + var detail = cockpit._enemy_details + assert(cockpit.SCREENS[2].encloses(Rect2(detail.position, detail.size))) + var label: Label = detail._label + assert(label.get_combined_minimum_size().y <= detail.size.y) + var font := label.get_theme_font("font") + for line in label.text.split("\n"): + assert(font.get_string_size(line, HORIZONTAL_ALIGNMENT_LEFT, -1, 8).x <= detail.size.x) + for sample in ["ZWYKŁE 999999", "GAMMA 999999", "999999", "PRĘDKOŚĆ: 999999", "DPS: 999999.9"]: + var width := 100.0 if sample == "999999" else 145.0 + var fitted: int = cockpit.fitted_font_size(sample, width, 19) + assert(cockpit.FONT.get_string_size(sample, HORIZONTAL_ALIGNMENT_LEFT, -1, fitted).x <= width) + await RenderingServer.frame_post_draw + var image := get_viewport().get_texture().get_image() + image.save_png("res://artifacts/cockpit_console_%dx%d.png" % [resolution.x, resolution.y]) + if resolution.x == 1280: + image.get_region(Rect2i(rect.grow(4))).save_png("res://artifacts/cockpit_console_review.png") + print("COCKPIT_CONSOLE_REVIEW_OK: 1280x720, 960x540, 800x600; screen bounds, six-digit counters, boss details and full text") + get_tree().quit() diff --git a/tests/previews/cockpit_console_review.gd.uid b/tests/previews/cockpit_console_review.gd.uid new file mode 100644 index 0000000..8a0a748 --- /dev/null +++ b/tests/previews/cockpit_console_review.gd.uid @@ -0,0 +1 @@ +uid://d1gwl78vt6434 diff --git a/tests/previews/cockpit_console_review.tscn b/tests/previews/cockpit_console_review.tscn new file mode 100644 index 0000000..620bcd1 --- /dev/null +++ b/tests/previews/cockpit_console_review.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/cockpit_console_review.gd" id="1"] +[node name="Review" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/compact_interface_review.gd b/tests/previews/compact_interface_review.gd new file mode 100644 index 0000000..377977a --- /dev/null +++ b/tests/previews/compact_interface_review.gd @@ -0,0 +1,69 @@ +extends Node +func settle() -> void: + for frame in 10: await get_tree().process_frame + +func shot(name: String) -> void: + await settle() + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/compact_interface_%s.png" % name) + +func check_panel(panel: PanelContainer) -> void: + var style = panel.get_theme_stylebox("panel") + if style is StyleBoxFlat: assert(style.bg_color.a <= 0.65) + var rect := panel.get_global_rect() + assert(rect.position.x >= 0 and rect.position.y >= 0) + assert(rect.end.x <= 1281 and rect.end.y <= 721) + +func _ready() -> void: + GameState.start_new_run() + var captain: Resource = GameState.captain + captain.parts = 100 + for mineral in preload("res://scripts/items/crafting_recipes.gd").MINERALS: captain.minerals[mineral] = 1000 + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + game.player.get_node("WeaponController").set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) + var hud := game.get_node("HUD") + await settle() + assert(hud._system_title.get_theme_font_size("font_size") <= 11) + assert(hud._system_badge.size.x <= 90 and hud._system_badge.size.y <= 40) + check_panel(hud._system_badge) + check_panel(hud._captain_panel) + hud._toggle_sidebar() + hud._toggle_inventory() + await settle() + check_panel(hud._sidebar) + check_panel(hud.inventory_panel) + check_panel(hud.inventory_panel.get_node("Contents/ResourceSection")) + await shot("hud") + hud.close_inventory() + hud._toggle_sidebar() + captain.learning_points = 1 + captain.prepare_skill_offers() + hud._captain_skills_ui.open_management() + await settle() + var skills: CanvasLayer = hud._captain_skills_ui + check_panel(skills._panel) + for label in skills._panel.find_children("*","Label",true,false): + assert(label.get_theme_font_size("font_size") <= 13) + await shot("skills") + skills._close() + game.get_node("PlanetExpeditions").open_freighter() + var screen: Control = game.get_node("PlanetExpeditions").screen + for section in ["hangar","workshop","storage","command","expansion_1","expansion_2","cabin_1"]: + screen._select_section(section) + await settle() + check_panel(screen._drawer) + assert(screen._drawer_title.get_theme_font_size("font_size") <= 13) + screen._select_section("workshop") + await shot("freighter") + screen._construct_room("expansion_2") + screen._select_section("expansion_2") + await shot("research") + screen.closed.emit() + game.free() + await get_tree().process_frame + print("COMPACT_INTERFACE_REVIEW_OK: small system badge, translucent HUD/inventory, captain skill cards, seven freighter sections and research") + get_tree().quit() diff --git a/tests/previews/compact_interface_review.gd.uid b/tests/previews/compact_interface_review.gd.uid new file mode 100644 index 0000000..de72dc0 --- /dev/null +++ b/tests/previews/compact_interface_review.gd.uid @@ -0,0 +1 @@ +uid://bkbjfce8mlref diff --git a/tests/previews/compact_interface_review.tscn b/tests/previews/compact_interface_review.tscn new file mode 100644 index 0000000..1278fe5 --- /dev/null +++ b/tests/previews/compact_interface_review.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/compact_interface_review.gd" id="1"] +[node name="CompactInterfaceReview" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/construction_layout_test.gd b/tests/previews/construction_layout_test.gd new file mode 100644 index 0000000..8231edb --- /dev/null +++ b/tests/previews/construction_layout_test.gd @@ -0,0 +1,30 @@ +extends Node +func _ready() -> void: + GameState.start_new_run() + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) + var manager := game.get_node("PlanetExpeditions") + assert(manager.freighter.find_children("*","Label",true,false).is_empty()) + manager.open_freighter() + var screen: Control = manager.screen + for section in ["expansion_1","expansion_2","expansion_3","cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"]: + screen._select_section(section) + for frame in 8: await get_tree().process_frame + for mineral in preload("res://scripts/items/crafting_recipes.gd").MINERALS: + var row: HBoxContainer = screen._content.find_child("Cost" + str(mineral).capitalize(), true, false) + assert(row != null and row.size.y <= 24) + var value: Label = row.get_node("Amount") + assert(value.text == "0 / 100" and value.autowrap_mode == TextServer.AUTOWRAP_OFF) + assert(row.get_global_rect().end.y < screen._drawer.get_global_rect().end.y - 50) + screen._select_section("expansion_1") + for frame in 8: await get_tree().process_frame + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/construction_layout_fixed.png") + manager.screen.closed.emit() + game.free() + await get_tree().process_frame + print("CONSTRUCTION_LAYOUT_OK: no freighter label, all eight rooms, five single-line costs, full cost table visible") + get_tree().quit() diff --git a/tests/previews/construction_layout_test.gd.uid b/tests/previews/construction_layout_test.gd.uid new file mode 100644 index 0000000..f806318 --- /dev/null +++ b/tests/previews/construction_layout_test.gd.uid @@ -0,0 +1 @@ +uid://dgv2as6o4gdds diff --git a/tests/previews/construction_layout_test.tscn b/tests/previews/construction_layout_test.tscn new file mode 100644 index 0000000..d41e26d --- /dev/null +++ b/tests/previews/construction_layout_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/construction_layout_test.gd" id="1"] +[node name="ConstructionLayoutTest" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/freighter_windows_review.gd b/tests/previews/freighter_windows_review.gd index 5c5b324..1e637f5 100644 --- a/tests/previews/freighter_windows_review.gd +++ b/tests/previews/freighter_windows_review.gd @@ -14,7 +14,7 @@ func review(id: String, phase: String) -> void: assert(rect.position.x >= 0 and rect.position.y >= 0) assert(rect.end.x <= get_viewport().get_visible_rect().size.x and rect.end.y <= get_viewport().get_visible_rect().size.y) var frame: StyleBoxFlat = screen._drawer.get_theme_stylebox("panel") - assert(frame.bg_color.a > 0.5 and frame.bg_color.a < 1) + assert(frame.bg_color.a >= 0.25 and frame.bg_color.a <= 0.64) for panel in screen._content.find_children("*","PanelContainer",true,false): var style = panel.get_theme_stylebox("panel") if style is StyleBoxFlat: assert(style.bg_color.a < 1) @@ -62,8 +62,8 @@ func _ready() -> void: var button: Button = screen._content.find_child(name,true,false) assert(not button.disabled) button.pressed.emit() - assert(captain.minerals.iron == 970) - assert(inventory.unlocked_cargo_rows == 2 and inventory.unlocked_weapon_slots == 2 and inventory.unlocked_extension_slots == 2) + assert(captain.minerals.iron == 60 and captain.minerals.aluminium == 110 and captain.minerals.titanium == 60) + assert(inventory.unlocked_cargo_slots == 6 and inventory.unlocked_weapon_slots == 2 and inventory.unlocked_extension_slots == 2) assert(gallery.save_png("res://artifacts/frigate_all_windows_review.png") == OK) screen.closed.emit() game.queue_free() diff --git a/tests/previews/weather_conditions_review.gd b/tests/previews/weather_conditions_review.gd new file mode 100644 index 0000000..50c7361 --- /dev/null +++ b/tests/previews/weather_conditions_review.gd @@ -0,0 +1,57 @@ +extends Node +const CONDITIONS := preload("res://scripts/planets/surface_weather_conditions.gd") +func _ready() -> void: + GameState.start_new_run() + var rng := RandomNumberGenerator.new() + rng.seed = 123 + for biome in range(6): + for sample in range(200): + var selected := CONDITIONS.pick(biome,rng) + assert(selected in CONDITIONS.CLIMATES[biome]) + if biome == 4: assert(CONDITIONS.DATA[selected].mode != "rain" and CONDITIONS.DATA[selected].mode != "snow") + if biome == 5: assert(CONDITIONS.DATA[selected].mode != "rain") + var gallery := Image.create(1440,810,false,Image.FORMAT_RGBA8) + var index := 0 + for condition in CONDITIONS.DATA: + var biome := 4 if condition == "dust_storm" else (5 if condition in ["snow","blizzard"] else 0) + var profile: Dictionary = preload("res://scripts/planets/planet_profiles.gd").generate(99,biome,"Pogoda") + profile.temperature = 75 if biome == 4 else (-35 if biome == 5 else 20) + var progress: Resource = GameState.captain.expedition + progress.lander_hp = 100 + assert(progress.begin_visit(profile)) + progress.visit_seed = 200+biome + var surface := preload("res://scripts/planets/surface_screen.gd").new() + surface.captain = GameState.captain + surface.progress = progress + add_child(surface) + surface.set_process(false) + surface.set_physics_process(false) + var weather: Node2D = surface.weather + weather.set_process(false) + assert(weather.set_condition(condition,true)) + assert(not weather.set_condition("invalid")) + for step in range(360): + weather._process(1.0/60) + weather._clouds._process(1.0/60) + assert(weather._particles.size() > 0 and weather._particles.size() <= weather.LIMIT) + assert(weather._clouds._banks.size() == 74) + assert(is_equal_approx(weather._clouds.darkness,float(CONDITIONS.DATA[condition].darkness))) + if condition == "storm": + weather.trigger_lightning() + weather.queue_redraw() + assert(weather._bolt.size() == 9 and weather._flash > 0) + surface._update_hud() + for frame in 5: await get_tree().process_frame + await RenderingServer.frame_post_draw + var screenshot := get_viewport().get_texture().get_image() + screenshot.save_png("res://artifacts/weather_condition_%s.png" % condition) + screenshot.convert(Image.FORMAT_RGBA8) + screenshot.resize(480,270,Image.INTERPOLATE_LANCZOS) + gallery.blit_rect(screenshot,Rect2i(0,0,480,270),Vector2i(index%3*480,index/3*270)) + index += 1 + progress.finish_visit(GameState.captain,false) + surface.free() + await get_tree().process_frame + gallery.save_png("res://artifacts/weather_conditions_review.png") + print("WEATHER_CONDITIONS_OK: nine states, climate restrictions, 74 cloud banks, bounded particles, lightning, visible status") + get_tree().quit() diff --git a/tests/previews/weather_conditions_review.gd.uid b/tests/previews/weather_conditions_review.gd.uid new file mode 100644 index 0000000..7b9df5b --- /dev/null +++ b/tests/previews/weather_conditions_review.gd.uid @@ -0,0 +1 @@ +uid://bg8r5fu5s67jj diff --git a/tests/previews/weather_conditions_review.tscn b/tests/previews/weather_conditions_review.tscn new file mode 100644 index 0000000..90637eb --- /dev/null +++ b/tests/previews/weather_conditions_review.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/weather_conditions_review.gd" id="1"] +[node name="WeatherConditionsReview" type="Node"] +script = ExtResource("1") diff --git a/tests/ships/alien_research_test.gd b/tests/ships/alien_research_test.gd new file mode 100644 index 0000000..cb21806 --- /dev/null +++ b/tests/ships/alien_research_test.gd @@ -0,0 +1,75 @@ +extends Node +const DATA := preload("res://scripts/planets/alien_research.gd") +func _ready() -> void: + GameState.start_new_run() + var progress: Resource = GameState.captain.expedition + progress.analysis_samples = 100 + assert(not DATA.purchase(progress, "hull")) + assert(DATA.purchase(progress, "general")) + assert(progress.analysis_samples == 90) + assert(not DATA.purchase(progress, "general")) + assert(DATA.purchase(progress, "hull")) + assert(progress.analysis_samples == 76) + assert(not DATA.purchase(progress, "hull_a")) + assert(progress.analysis_samples == 76) + assert(is_equal_approx(DATA.bonus(progress, "hull"), 0.1)) + progress.alien_skills["hull_a"] = true + assert(is_equal_approx(DATA.bonus(progress, "hull"), 0.1)) + assert(DATA.learned_count(progress) == 2) + progress.analysis_samples = 0 + assert(not DATA.purchase(progress, "hull_b")) + progress.analysis_samples = 76 + assert(ResourceSaver.save(progress, "res://tmp/research_roundtrip.tres") == OK) + var restored: Resource = ResourceLoader.load("res://tmp/research_roundtrip.tres", "", ResourceLoader.CACHE_MODE_IGNORE) + assert(restored.alien_skills == progress.alien_skills and restored.analysis_samples == 76) + DirAccess.remove_absolute("res://tmp/research_roundtrip.tres") + var enemy := preload("res://scenes/game/enemy_ship.tscn").instantiate() + add_child(enemy) + enemy.set_process(false) + enemy.set_physics_process(false) + enemy.absorption = Vector3.ZERO + enemy.shields = 5 + enemy.hull = 100 + enemy.take_weapon_hit(10, false) + assert(is_equal_approx(enemy.hull, 94.5)) + progress.analysis_samples = 100 + assert(DATA.purchase(progress, "shields")) + assert(DATA.purchase(progress, "weapons")) + assert(is_equal_approx(enemy.get_shot_damage(), enemy.weapon_damage * 0.9)) + enemy.shields = 5.5 + enemy.hull = 100 + enemy.take_weapon_hit(10, false) + assert(is_equal_approx(enemy.hull, 94.5)) + enemy.free() + var screen := preload("res://scenes/planets/freighter_interior.tscn").instantiate() + progress.freighter_rooms["expansion_2"] = "alien_research" + add_child(screen) + screen._select_section("expansion_2") + for frame in 8: await get_tree().process_frame + assert(screen._drawer.size.x == 490 and screen._drawer.size.y == 430) + var skill_buttons: Array[Node] = screen._content.find_children("*", "Button", true, false) + assert(skill_buttons.size() == 10) + for button in skill_buttons: + assert(is_equal_approx(button.size.x, 56) and button.tooltip_text.contains("\n")) + assert(button.get_child_count() <= 3) + if "_" in str(button.name): + assert(button.disabled and button.get_child_count() == 1) + var tooltip: Object = skill_buttons[0]._make_custom_tooltip(skill_buttons[0].tooltip_text) + assert(tooltip is PanelContainer) + tooltip.free() + print("ALIEN_RESEARCH_TEST_OK") + if DisplayServer.get_name() != "headless": + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/alien_research.png") + var motion := InputEventMouseMotion.new() + motion.position = skill_buttons[0].get_global_rect().get_center() + motion.global_position = motion.position + get_viewport().push_input(motion) + await get_tree().create_timer(0.9).timeout + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/alien_research_hover.png") + screen.free() + for child in get_children(): child.queue_free() + await get_tree().process_frame + get_tree().quit() + diff --git a/tests/ships/alien_research_test.gd.uid b/tests/ships/alien_research_test.gd.uid new file mode 100644 index 0000000..7cd90df --- /dev/null +++ b/tests/ships/alien_research_test.gd.uid @@ -0,0 +1 @@ +uid://dtxwv3s3uw67f diff --git a/tests/ships/alien_research_test.tscn b/tests/ships/alien_research_test.tscn new file mode 100644 index 0000000..17254fe --- /dev/null +++ b/tests/ships/alien_research_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/ships/alien_research_test.gd" id="1"] +[node name="AlienResearchTest" type="Node"] +script = ExtResource("1") diff --git a/tests/ships/construction_resources_test.gd b/tests/ships/construction_resources_test.gd new file mode 100644 index 0000000..611b952 --- /dev/null +++ b/tests/ships/construction_resources_test.gd @@ -0,0 +1,33 @@ +extends Node +const RECIPES := preload("res://scripts/items/crafting_recipes.gd") +func _ready() -> void: + GameState.start_new_run() + var captain: Resource = GameState.captain + var hud := preload("res://scripts/game/flight_hud.gd").new() + hud._give_debug_resources() + for mineral in preload("res://scripts/planets/planet_rewards.gd").MATERIAL_KEYS: + if mineral != "parts": assert(captain.minerals[mineral] == 100) + assert(captain.parts == 100 and captain.expedition.analysis_samples == 100) + hud._give_debug_resources() + assert(captain.parts == 200 and captain.expedition.analysis_samples == 200) + hud.free() + var screen := preload("res://scenes/planets/freighter_interior.tscn").instantiate() + add_child(screen) + captain.minerals.iron = 99 + screen._construct_room("expansion_2") + assert(not screen.deck.is_built("expansion_2") and captain.minerals.titanium == 200) + captain.minerals.iron = 200 + screen._select_section("expansion_2") + screen._construct_room("expansion_2") + assert(screen.deck.is_built("expansion_2")) + for mineral in RECIPES.MINERALS: assert(captain.minerals[mineral] == 100) + assert(captain.minerals.silicon == 200 and captain.parts == 200) + screen._construct_room("expansion_2") + assert(captain.minerals.iron == 100) + screen._construct_room("cabin_1") + for mineral in RECIPES.MINERALS: assert(captain.minerals[mineral] == 0) + screen._select_section("storage") + for frame in 5: await get_tree().process_frame + print("CONSTRUCTION_RESOURCES_TEST_OK") + screen.free() + get_tree().quit() diff --git a/tests/ships/construction_resources_test.gd.uid b/tests/ships/construction_resources_test.gd.uid new file mode 100644 index 0000000..42e4b86 --- /dev/null +++ b/tests/ships/construction_resources_test.gd.uid @@ -0,0 +1 @@ +uid://cpllrxqh56edc diff --git a/tests/ships/construction_resources_test.tscn b/tests/ships/construction_resources_test.tscn new file mode 100644 index 0000000..8e83911 --- /dev/null +++ b/tests/ships/construction_resources_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/ships/construction_resources_test.gd" id="1"] +[node name="ConstructionResourcesTest" type="Node"] +script = ExtResource("1") diff --git a/tests/ships/freighter_storage_test.gd b/tests/ships/freighter_storage_test.gd index a2dc19e..d679114 100644 --- a/tests/ships/freighter_storage_test.gd +++ b/tests/ships/freighter_storage_test.gd @@ -17,15 +17,16 @@ func _ready() -> void: await settle() var inv: ShipInventory = game.player.get_node("ShipInventory") var captain := GameState.captain - assert(inv.get_cargo_capacity() == 5 and inv.unlocked_cargo_rows == 1) + assert(inv.get_cargo_capacity() == 5 and inv.unlocked_cargo_slots == 5) var items: Array[ItemInstance] = [] for index in 6: items.append(preload("res://scripts/items/item_generator.gd").generate_for_definition(preload("res://resources/items/reinforced_shield.tres"),index+1)) for index in 5: assert(inv.add_item(items[index])) assert(not inv.add_item(items[5]) and inv.cargo[5] == null) assert(not inv.can_move_item("cargo",0,"cargo",5)) - captain.minerals["iron"] = 100 - assert(not inv.unlock_cargo_row(captain)) + for mineral in preload("res://scripts/items/crafting_recipes.gd").MINERALS: + captain.minerals[mineral] = 100 + assert(not inv.unlock_slot("cargo",captain)) assert(not inv.store_on_freighter(0,items[0],captain)) var manager := game.get_node("PlanetExpeditions") manager.open_freighter() @@ -46,11 +47,14 @@ func _ready() -> void: assert(find_button("← ODBIERZ").disabled) screen._select_section("hangar") captain.minerals["iron"] = 9 - assert(not inv.unlock_cargo_row(captain) and captain.minerals.iron == 9) - captain.minerals["iron"] = 30 + assert(not inv.unlock_slot("cargo",captain) and captain.minerals.iron == 9) + captain.minerals["iron"] = 100 + captain.minerals["aluminium"] = 49 + assert(not inv.unlock_slot("cargo",captain) and captain.minerals.iron == 100) + captain.minerals["aluminium"] = 50 screen._refresh() screen._content.find_child("UnlockCargo",true,false).pressed.emit() - assert(inv.get_cargo_capacity() == 10 and captain.minerals.iron == 20) + assert(inv.get_cargo_capacity() == 6 and captain.minerals.iron == 0 and captain.minerals.aluminium == 0) screen._select_section("storage") find_button("← ODBIERZ").pressed.emit() assert(inv.cargo[5] == items[0] and captain.expedition.freighter_storage.is_empty()) @@ -61,10 +65,14 @@ func _ready() -> void: await settle() await RenderingServer.frame_post_draw get_viewport().get_texture().get_image().save_png("res://artifacts/freighter_storage.png") - assert(inv.unlock_cargo_row(captain) and inv.unlock_cargo_row(captain)) + captain.minerals.iron = 1400 + captain.minerals.aluminium = 700 + for slot in range(6,20): + assert(inv.get_cargo_capacity() == slot) + assert(inv.unlock_slot("cargo",captain)) assert(inv.get_cargo_capacity() == 20 and captain.minerals.iron == 0) captain.minerals["iron"] = 10 - assert(not inv.unlock_cargo_row(captain) and captain.minerals.iron == 10) + assert(not inv.unlock_slot("cargo",captain) and captain.minerals.iron == 10) assert(ResourceSaver.save(captain.expedition,"user://freighter_storage_test.tres") == OK) var restored: Resource = ResourceLoader.load("user://freighter_storage_test.tres","",ResourceLoader.CACHE_MODE_IGNORE) assert(restored.freighter_storage.size() == 2) @@ -85,5 +93,5 @@ func _ready() -> void: game.free() GameState.start_new_run() assert(GameState.captain.expedition.freighter_storage.is_empty()) - print("FREIGHTER STORAGE PASS: 5 starting cargo cells, locked loot/drop, row costs/limits, construction, bidirectional transfers, full cargo, stale buttons, resource serialization, system persistence, new run reset") + print("FREIGHTER STORAGE PASS: 5 starting cargo cells, locked loot/drop, single slot costs/limits, construction, bidirectional transfers, full cargo, stale buttons, resource serialization, system persistence, new run reset") get_tree().quit() diff --git a/tests/ships/ship_statistics_test.gd b/tests/ships/ship_statistics_test.gd new file mode 100644 index 0000000..b556e00 --- /dev/null +++ b/tests/ships/ship_statistics_test.gd @@ -0,0 +1,78 @@ +extends Node +const GENERATOR := preload("res://scripts/items/item_generator.gd") +func settle() -> void: + for frame in 8: await get_tree().process_frame + +func shot(path: String) -> void: + await settle() + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png(path) + +func _ready() -> void: + GameState.start_new_run() + GameState.system_level = 7 + GameState.selected_ship_path = "res://assets/Ships/player/bastion.png" + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + game.player.get_node("WeaponController").set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) + var hud := game.get_node("HUD") + var ship: CharacterBody2D = game.player + var inv: ShipInventory = ship.get_node("ShipInventory") + inv.unlocked_weapon_slots = 3 + inv.unlocked_extension_slots = 2 + for i in range(3): + inv.weapon_slots[i] = GENERATOR.generate_for_definition(load("res://resources/items/" + ["plasma_cannon", "gamma_cannon", "missile_launcher"][i] + ".tres"), 7) + inv.extension_slots[0] = GENERATOR.generate_for_definition(preload("res://resources/items/teleport.tres"),7) + inv.extension_slots[1] = GENERATOR.generate_for_definition(preload("res://resources/items/recycler.tres"),7) + for definition in GENERATOR.DEFINITIONS: + var module_index := inv.MODULE_CATEGORIES.find(definition.category) + if module_index >= 0 and inv.module_slots[module_index] == null: + inv.module_slots[module_index] = GENERATOR.generate_for_definition(definition,7) + inv._recalculate_ship_stats() + inv.inventory_changed.emit() + await settle() + assert(hud._system_title.text == "System 7") + assert(is_equal_approx(hud._sidebar_toggle.size.x, 221) and is_equal_approx(hud._sidebar_toggle.size.y, 71.5)) + assert(hud._system_badge.position.x > hud._captain_panel.get_global_rect().end.x) + hud._sidebar_toggle.pressed.emit() + var button := hud._sidebar.find_child("StatisticsButton",true,false) as Button + assert(button != null and button.is_visible_in_tree()) + await shot("res://artifacts/ship_hud.png") + button.pressed.emit() + await settle() + var stats: PanelContainer = hud._ship_statistics + assert(stats.visible and stats.size.x == 690) + assert(stats._bindings.has("hull") and stats._bindings.has("critical") and stats._bindings.has("cargo")) + ship.absorption = Vector3(7,11,13) + ship.hull = 25 + stats._refresh_values() + assert(stats._bindings.hull.label.text.begins_with("25 /")) + assert(stats._bindings.kinetic_absorption.label.text == "7.0%") + assert(stats._bindings.radiation_absorption.label.text == "13.0%") + assert(stats._bindings.dps.label.text == "%.1f" % inv.get_total_dps()) + assert(stats.size.y == 490 and stats.position.y >= 0) + ship.hull = ship.max_hull * 0.75 + await shot("res://artifacts/ship_statistics_parameters.png") + stats._select_tab("weapons") + for i in range(3): + assert(stats._bindings["weapon_dps_%d" % i].label.text == "%.1f" % inv.get_weapon_dps(i)) + assert(is_equal_approx(inv.get_total_dps(),inv.get_weapon_dps(0)+inv.get_weapon_dps(1)+inv.get_weapon_dps(2))) + await shot("res://artifacts/ship_statistics_weapons.png") + stats._select_tab("equipment") + assert(stats._bindings.has("extension_0")) + await shot("res://artifacts/ship_statistics_systems.png") + GameState.system_level = 61 + await settle() + assert(hud._system_title.text == "System 61" and hud._system_mode.text == "HARD") + var event := InputEventKey.new() + event.pressed = true + event.keycode = KEY_ESCAPE + stats._unhandled_key_input(event) + assert(not stats.visible) + game.free() + await get_tree().process_frame + print("SHIP_STATISTICS_TEST_OK: HUD badge, statistics button, live values, absorption, per-weapon DPS, tabs, cooldowns and close") + get_tree().quit() diff --git a/tests/ships/ship_statistics_test.gd.uid b/tests/ships/ship_statistics_test.gd.uid new file mode 100644 index 0000000..aab39fa --- /dev/null +++ b/tests/ships/ship_statistics_test.gd.uid @@ -0,0 +1 @@ +uid://cssxoppygq5ae diff --git a/tests/ships/ship_statistics_test.tscn b/tests/ships/ship_statistics_test.tscn new file mode 100644 index 0000000..eb796ce --- /dev/null +++ b/tests/ships/ship_statistics_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/ships/ship_statistics_test.gd" id="1"] +[node name="ShipStatisticsTest" type="Node"] +script = ExtResource("1") diff --git a/tests/ships/slot_unlock_test.gd b/tests/ships/slot_unlock_test.gd index 0b85162..eedfea4 100644 --- a/tests/ships/slot_unlock_test.gd +++ b/tests/ships/slot_unlock_test.gd @@ -20,6 +20,7 @@ func _ready() -> void: inv.cargo[1] = extension assert(inv.can_move_item("cargo",1,"extension",0)) assert(not inv.can_move_item("cargo",1,"extension",1)) + captain.minerals["titanium"] = 600 captain.minerals["iron"] = 100 assert(not inv.unlock_slot("weapon",captain),"Unlock requires docking") assert(captain.minerals.iron == 100) @@ -27,11 +28,11 @@ func _ready() -> void: manager.open_freighter() var screen: Control = manager.screen screen._select_section("hangar") - captain.minerals["iron"] = 9 + captain.minerals["titanium"] = 99 screen._refresh() assert(not inv.unlock_slot("weapon",captain)) - assert(captain.minerals.iron == 9 and inv.unlocked_weapon_slots == 1) - captain.minerals["iron"] = 60 + assert(captain.minerals.titanium == 99 and inv.unlocked_weapon_slots == 1) + captain.minerals["titanium"] = 600 screen._refresh() await settle() await RenderingServer.frame_post_draw @@ -41,15 +42,29 @@ func _ready() -> void: if node.name == "UnlockWeapon": button = node assert(button != null and not button.disabled) button.pressed.emit() - assert(inv.unlocked_weapon_slots == 2 and captain.minerals.iron == 50) + assert(inv.unlocked_weapon_slots == 2 and captain.minerals.titanium == 500) assert(inv.can_move_item("cargo",0,"weapon",1)) assert(inv.unlock_slot("weapon",captain)) - for index in 4: assert(inv.unlock_slot("extension",captain)) + assert(captain.minerals.titanium == 0) + for mineral in ["iron", "aluminium", "titanium"]: captain.minerals[mineral] = 600 + for index in 4: + var cost := 40 * (1 << index) + assert(inv.get_slot_unlock_cost("extension") == {"iron":cost, "aluminium":cost, "titanium":cost}) + var stock: Dictionary = captain.minerals.duplicate() + captain.minerals.aluminium = cost - 1 + assert(not inv.unlock_slot("extension", captain)) + assert(captain.minerals.iron == stock.iron and captain.minerals.titanium == stock.titanium) + captain.minerals.aluminium = stock.aluminium + assert(inv.unlock_slot("extension",captain)) assert(inv.unlocked_weapon_slots == 3 and inv.unlocked_extension_slots == 5) - assert(captain.minerals.iron == 0) + assert(captain.minerals.iron == 0 and captain.minerals.aluminium == 0 and captain.minerals.titanium == 0) captain.minerals["iron"] = 100 assert(not inv.unlock_slot("weapon",captain) and not inv.unlock_slot("extension",captain)) assert(not inv.unlock_slot("module",captain) and captain.minerals.iron == 100) + captain.minerals.iron = 100 + captain.minerals.aluminium = 50 + assert(inv.unlock_slot("cargo", captain) and inv.get_cargo_capacity() == 6) + assert(not inv.is_slot_unlocked("cargo", 6)) inv.preserve_for_restart() screen.closed.emit() game.free() @@ -57,7 +72,16 @@ func _ready() -> void: add_child(game) await settle() inv = game.player.get_node("ShipInventory") - assert(inv.unlocked_weapon_slots == 3 and inv.unlocked_extension_slots == 5) + assert(inv.unlocked_weapon_slots == 3 and inv.unlocked_extension_slots == 5 and inv.get_cargo_capacity() == 6) + inv.preserve_for_restart() + GameState.restart_inventory.erase("unlocked_cargo_slots") + GameState.restart_inventory["unlocked_cargo_rows"] = 2 + game.free() + game = preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + inv = game.player.get_node("ShipInventory") + assert(inv.get_cargo_capacity() == 10, "Legacy two-row progress retains ten slots") game.free() GameState.start_new_run() game = preload("res://scenes/game/game.tscn").instantiate() @@ -66,5 +90,5 @@ func _ready() -> void: inv = game.player.get_node("ShipInventory") assert(inv.unlocked_weapon_slots == 1 and inv.unlocked_extension_slots == 1) game.free() - print("SLOT UNLOCK PASS: starter 1/1, locked mounting, dock requirement, affordability, hangar button, 10 iron per slot, limits 3/5, restart persistence, new run reset") + print("SLOT UNLOCK PASS: starter 1/1, locked mounting, dock requirement, affordability, hangar button, new resource costs, doubling extensions, single cargo slot, legacy migration, limits 3/5, restart persistence, new run reset") get_tree().quit() diff --git a/tmp/boss_regeneration-errors.log b/tmp/boss_regeneration-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/boss_regeneration.log b/tmp/boss_regeneration.log new file mode 100644 index 0000000..1026c5b --- /dev/null +++ b/tmp/boss_regeneration.log @@ -0,0 +1,6 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6571 +[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot +ENEMY_REPAIR_NOTIFICATION_TEST: PASS 1%/s, retreat threshold, caps, dead enemy, boss regeneration disabled, elite regeneration, notification reset diff --git a/tmp/captain_import-errors.log b/tmp/captain_import-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/captain_import.log b/tmp/captain_import.log new file mode 100644 index 0000000..e8d59ba --- /dev/null +++ b/tmp/captain_import.log @@ -0,0 +1,39 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[ 0% ] first_scan_filesystem | Started Project initialization (5 steps) +[ 0% ] first_scan_filesystem | Scanning file structure... +[ 16% ] first_scan_filesystem | Loading global class names... +[ 33% ] first_scan_filesystem | Verifying GDExtensions... +[ 50% ] first_scan_filesystem | Creating autoload scripts... +[ 66% ] first_scan_filesystem | Initializing plugins... +Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com +[MCPExtensions] Hot-reload watcher active +[MCPServer] port: scanning 6550-6560 (default) +[MCPServer] session token written to user://addons/godot_mcp_toolkit/project_instance_32cc2271ac67/mcp_token +[MCPServer] listening on 127.0.0.1:6551 +[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551 +[ 83% ] first_scan_filesystem | Starting file scan... +[ DONE ] first_scan_filesystem + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Preparing files to reimport... +[ 0% ] reimport | Executing pre-reimport operations... +[ 0% ] reimport | captain_ring_frame.png +[ 50% ] reimport | Finalizing Asset Import... +[ DONE ] reimport + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Executing post-reimport operations... +[ DONE ] reimport + +[ 0% ] loading_editor_layout | Started Loading editor (5 steps) +[ 0% ] loading_editor_layout | Loading editor layout... +[ 16% ] loading_editor_layout | Loading docks... +[ 33% ] loading_editor_layout | Reopening scenes... +[ 50% ] loading_editor_layout | Loading central editor layout... +[ 66% ] loading_editor_layout | Loading plugin window layout... +[ 83% ] loading_editor_layout | Editor layout ready. +[ DONE ] loading_editor_layout + +[MCPServer] stopped +[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot diff --git a/tmp/captain_layout.cjs b/tmp/captain_layout.cjs new file mode 100644 index 0000000..b4985f3 --- /dev/null +++ b/tmp/captain_layout.cjs @@ -0,0 +1,8 @@ +const fs=require('fs');const p='scripts/ui/captain_panel.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n'); +s=s.replace('Rect2(79, 10, 83, 17)','Rect2(79, 14, 83, 15)'); +s=s.replace('Rect2(79, 11, 77, 15)','Rect2(79, 14, 77, 13)').replace('Rect2(164, 11, 63, 15)','Rect2(164, 14, 63, 13)'); +s=s.replace('Rect2(79, 27, 148, 15)','Rect2(79, 28, 148, 13)').replace('Rect2(79, 42, 148, 12)','Rect2(79, 40, 148, 10)'); +s=s.replace('Rect2(79, 56, 148, 4)','Rect2(79, 52, 148, 3)').replace('xp_bar.custom_minimum_size.y = 4','xp_bar.custom_minimum_size.y = 3'); +s=s.replace('_place(portrait, Rect2(9, 9, 54, 54))','_place(portrait, Rect2(16, 12, 54, 54))\n\tportrait.scale = Vector2.ONE * 0.85'); +s=s.replace('$Contents.move_child(artwork, 0)','$Contents.move_child(artwork, $Contents.get_child_count() - 1)'); +s=s.replace('Rect2(69, 10, 165, 52)','Rect2(73, 17, 160, 36)');fs.writeFileSync(p,s); diff --git a/tmp/captain_review-errors.log b/tmp/captain_review-errors.log new file mode 100644 index 0000000..dd33cf9 --- /dev/null +++ b/tmp/captain_review-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/captain_ring_review.gd:7) diff --git a/tmp/captain_review.log b/tmp/captain_review.log new file mode 100644 index 0000000..83bdac2 --- /dev/null +++ b/tmp/captain_review.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +CAPTAIN_RING_REVIEW_OK: compact panel, live XP and credits, equipment click, level-up access diff --git a/tmp/captain_ring_review.gd b/tmp/captain_ring_review.gd new file mode 100644 index 0000000..02158b8 --- /dev/null +++ b/tmp/captain_ring_review.gd @@ -0,0 +1,37 @@ +extends Node +func _ready() -> void: + GameState.start_new_run() + GameState.captain.credits = 12540 + GameState.captain.experience = 75 + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) + for frame in 15: await get_tree().process_frame + var panel = game.get_node("HUD")._captain_panel + assert(panel.size.y <= 95) + assert(panel.xp_bar.value == 75) + assert(panel.credits_label.text == "Kredyty: 12540") + assert(panel.size.x > 317) + var equipped := [false] + panel.equipment_requested.connect(func(): equipped[0] = true) + var click := InputEventMouseButton.new() + click.button_index = MOUSE_BUTTON_LEFT + click.pressed = true + panel._gui_input(click) + assert(equipped[0]) + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().get_region(Rect2i(panel.get_global_rect().grow(4))).save_png("res://artifacts/captain_ring_panel.png") + get_viewport().get_texture().get_image().save_png("res://artifacts/captain_ring_hud.png") + var cockpit = game.get_node("HUD")._cockpit + get_viewport().get_texture().get_image().get_region(Rect2i(cockpit.get_global_rect().grow(4))).save_png("res://artifacts/cockpit_frame_review.png") + GameState.captain.learning_points = 1 + GameState.captain.emit_changed() + for frame in 5: await get_tree().process_frame + assert(panel._level_up_button.visible) + assert(panel.size.y <= 95) + panel._level_up_button.pressed.emit() + assert(game.get_node("HUD/CaptainSkills")._screen.visible) + print("CAPTAIN_RING_REVIEW_OK: compact panel, live XP and credits, equipment click, level-up access") + get_tree().quit() diff --git a/tmp/captain_ring_review.gd.uid b/tmp/captain_ring_review.gd.uid new file mode 100644 index 0000000..fc986d3 --- /dev/null +++ b/tmp/captain_ring_review.gd.uid @@ -0,0 +1 @@ +uid://bl6lt47g3tflo diff --git a/tmp/captain_ring_review.tscn b/tmp/captain_ring_review.tscn new file mode 100644 index 0000000..ee3f090 --- /dev/null +++ b/tmp/captain_ring_review.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tmp/captain_ring_review.gd" id="1"] +[node name="Review" type="Node"] +script = ExtResource("1") diff --git a/tmp/captain_scene.cjs b/tmp/captain_scene.cjs new file mode 100644 index 0000000..809e905 --- /dev/null +++ b/tmp/captain_scene.cjs @@ -0,0 +1 @@ +const fs=require('fs');let p='scenes/ui/captain_panel.tscn';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n').replace('custom_minimum_size = Vector2(260, 210)','custom_minimum_size = Vector2(244, 72)').replace('name="Contents" type="VBoxContainer"','name="Contents" type="Control"').replace('name="Header" type="HBoxContainer"','name="Header" type="Control"').replace('name="Wallet" type="HBoxContainer"','name="Wallet" type="Control"');fs.writeFileSync(p,s); diff --git a/tmp/captain_shift-errors.log b/tmp/captain_shift-errors.log new file mode 100644 index 0000000..853f87a --- /dev/null +++ b/tmp/captain_shift-errors.log @@ -0,0 +1,6 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/captain_ring_review.gd:7) +WARNING: 4 ObjectDB instances were leaked at exit (run with `--verbose` for details). + at: cleanup (core/object/object.cpp:2536) diff --git a/tmp/captain_shift.log b/tmp/captain_shift.log new file mode 100644 index 0000000..83bdac2 --- /dev/null +++ b/tmp/captain_shift.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +CAPTAIN_RING_REVIEW_OK: compact panel, live XP and credits, equipment click, level-up access diff --git a/tmp/captain_skills_review-errors.log b/tmp/captain_skills_review-errors.log new file mode 100644 index 0000000..6ac8135 --- /dev/null +++ b/tmp/captain_skills_review-errors.log @@ -0,0 +1,15 @@ +SCRIPT ERROR: Assertion failed. + at: _test_offers (res://tests/captain/captain_skills_test.gd:178) + GDScript backtrace (most recent call first): + [0] _test_offers (res://tests/captain/captain_skills_test.gd:178) + [1] _ready (res://tests/captain/captain_skills_test.gd:8) +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tests/captain/captain_skills_test.gd:11) +SCRIPT ERROR: Assertion failed. + at: _ready (res://tests/captain/captain_skills_test.gd:47) + GDScript backtrace (most recent call first): + [0] _ready (res://tests/captain/captain_skills_test.gd:47) +WARNING: 4 ObjectDB instances were leaked at exit (run with `--verbose` for details). + at: cleanup (core/object/object.cpp:2536) diff --git a/tmp/captain_skills_review.log b/tmp/captain_skills_review.log new file mode 100644 index 0000000..f39e653 --- /dev/null +++ b/tmp/captain_skills_review.log @@ -0,0 +1,5 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot diff --git a/tmp/cockpit_frame.cjs b/tmp/cockpit_frame.cjs new file mode 100644 index 0000000..890a92b --- /dev/null +++ b/tmp/cockpit_frame.cjs @@ -0,0 +1,2 @@ +const fs=require('fs');let p='scripts/ui/flight_cockpit.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');s=s.replace('var _inventory: ShipInventory','var _inventory: ShipInventory\nvar _frame: Texture2D\nvar _frame_region := Rect2()');s=s.replace('\tmouse_filter = Control.MOUSE_FILTER_IGNORE','\tmouse_filter = Control.MOUSE_FILTER_IGNORE\n\t_frame = load("res://assets/ui/frames/cockpit_frame.png") as Texture2D\n\tvar source := _frame.get_image()\n\tif source.is_compressed(): source.decompress()\n\t_frame_region = Rect2(source.get_used_rect())');s=s.replace('\tdraw_string(FONT, point, value,','\tdraw_string_outline(FONT, point, value, HORIZONTAL_ALIGNMENT_CENTER, width, font_size, 2, Color("030a12cc"))\n\tdraw_string(FONT, point, value,');s=s.replace('Color(0.025, 0.041, 0.063, 0.78)','Color(0.025, 0.041, 0.063, 0.30)');s=s.replace(/\tvar closed := outline.duplicate\(\)\n\tclosed.append\(outline\[0\]\)\n\tdraw_polyline\(closed[^\n]*\n\tdraw_line\(Vector2\(28[^\n]*\n/,'\tif _frame != null:\n\t\tdraw_texture_rect_region(_frame, Rect2(Vector2.ZERO, size), _frame_region)\n');fs.writeFileSync(p,s); +p='scripts/ui/captain_panel.gd';s=fs.readFileSync(p,'utf8').replace('"font_size", 9','"font_size", 10').replace('"font_size", 10)\n\tcredits_label.text','"font_size", 11)\n\tcredits_label.text').replace('"font_size", 8','"font_size", 9');fs.writeFileSync(p,s); diff --git a/tmp/cockpit_import-errors.log b/tmp/cockpit_import-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/cockpit_import.log b/tmp/cockpit_import.log new file mode 100644 index 0000000..95736c6 --- /dev/null +++ b/tmp/cockpit_import.log @@ -0,0 +1,39 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[ 0% ] first_scan_filesystem | Started Project initialization (5 steps) +[ 0% ] first_scan_filesystem | Scanning file structure... +[ 16% ] first_scan_filesystem | Loading global class names... +[ 33% ] first_scan_filesystem | Verifying GDExtensions... +[ 50% ] first_scan_filesystem | Creating autoload scripts... +[ 66% ] first_scan_filesystem | Initializing plugins... +Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com +[MCPExtensions] Hot-reload watcher active +[MCPServer] port: scanning 6550-6560 (default) +[MCPServer] session token written to user://addons/godot_mcp_toolkit/project_instance_32cc2271ac67/mcp_token +[MCPServer] listening on 127.0.0.1:6551 +[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551 +[ 83% ] first_scan_filesystem | Starting file scan... +[ DONE ] first_scan_filesystem + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Preparing files to reimport... +[ 0% ] reimport | Executing pre-reimport operations... +[ 0% ] reimport | cockpit_frame.png +[ 50% ] reimport | Finalizing Asset Import... +[ DONE ] reimport + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Executing post-reimport operations... +[ DONE ] reimport + +[ 0% ] loading_editor_layout | Started Loading editor (5 steps) +[ 0% ] loading_editor_layout | Loading editor layout... +[ 16% ] loading_editor_layout | Loading docks... +[ 33% ] loading_editor_layout | Reopening scenes... +[ 50% ] loading_editor_layout | Loading central editor layout... +[ 66% ] loading_editor_layout | Loading plugin window layout... +[ 83% ] loading_editor_layout | Editor layout ready. +[ DONE ] loading_editor_layout + +[MCPServer] stopped +[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot diff --git a/tmp/cockpit_layout.cjs b/tmp/cockpit_layout.cjs new file mode 100644 index 0000000..6c9d59b --- /dev/null +++ b/tmp/cockpit_layout.cjs @@ -0,0 +1,2 @@ +const fs=require('fs');let p='scripts/ui/flight_cockpit.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');s=s.replace(/\tvar source := _frame.get_image\(\)\n\tif source.is_compressed\(\): source.decompress\(\)\n\t_frame_region = Rect2\(source.get_used_rect\(\)\)/,'\t# Ignore the transparent canvas padding around the wide generated border.\n\t_frame_region = Rect2(5, 202, 2163, 304)');s=s.replace('Rect2(20 + index * 60, 12, 52, 52)','Rect2(32 + index * 60, 18, 52, 52)');fs.writeFileSync(p,s); +p='tmp/captain_ring_review.gd';s=fs.readFileSync(p,'utf8').replace(/panel.size.y <= 82/g,'panel.size.y <= 95').replace('var equipped := [false]','assert(panel.size.x > 317)\n\tvar equipped := [false]');s=s.replace('GameState.captain.learning_points = 1','var cockpit = game.get_node("HUD")._cockpit\n\tget_viewport().get_texture().get_image().get_region(Rect2i(cockpit.get_global_rect().grow(4))).save_png("res://artifacts/cockpit_frame_review.png")\n\tGameState.captain.learning_points = 1');fs.writeFileSync(p,s); diff --git a/tmp/cockpit_review-errors.log b/tmp/cockpit_review-errors.log new file mode 100644 index 0000000..dd33cf9 --- /dev/null +++ b/tmp/cockpit_review-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/captain_ring_review.gd:7) diff --git a/tmp/cockpit_review.log b/tmp/cockpit_review.log new file mode 100644 index 0000000..5043011 --- /dev/null +++ b/tmp/cockpit_review.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6571 +[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot +CAPTAIN_RING_REVIEW_OK: compact panel, live XP and credits, equipment click, level-up access diff --git a/tmp/console_fit-errors.log b/tmp/console_fit-errors.log new file mode 100644 index 0000000..c54c199 --- /dev/null +++ b/tmp/console_fit-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tests/previews/cockpit_console_review.gd:9) diff --git a/tmp/console_fit.log b/tmp/console_fit.log new file mode 100644 index 0000000..15586eb --- /dev/null +++ b/tmp/console_fit.log @@ -0,0 +1,10 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +DETAIL_SIZE (92.0, 42.0) target (145.0, 42.0) font 8 +DETAIL_SIZE (92.0, 42.0) target (145.0, 42.0) font 8 +DETAIL_SIZE (92.0, 42.0) target (145.0, 42.0) font 8 +COCKPIT_CONSOLE_REVIEW_OK: 1280x720, 960x540, 800x600; screen bounds, six-digit counters, boss details and full text diff --git a/tmp/console_import-errors.log b/tmp/console_import-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/console_import.log b/tmp/console_import.log new file mode 100644 index 0000000..6a89643 --- /dev/null +++ b/tmp/console_import.log @@ -0,0 +1,39 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[ 0% ] first_scan_filesystem | Started Project initialization (5 steps) +[ 0% ] first_scan_filesystem | Scanning file structure... +[ 16% ] first_scan_filesystem | Loading global class names... +[ 33% ] first_scan_filesystem | Verifying GDExtensions... +[ 50% ] first_scan_filesystem | Creating autoload scripts... +[ 66% ] first_scan_filesystem | Initializing plugins... +Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com +[MCPExtensions] Hot-reload watcher active +[MCPServer] port: scanning 6550-6560 (default) +[MCPServer] session token written to user://addons/godot_mcp_toolkit/project_instance_32cc2271ac67/mcp_token +[MCPServer] listening on 127.0.0.1:6551 +[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551 +[ 83% ] first_scan_filesystem | Starting file scan... +[ DONE ] first_scan_filesystem + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Preparing files to reimport... +[ 0% ] reimport | Executing pre-reimport operations... +[ 0% ] reimport | cockpit_console.png +[ 50% ] reimport | Finalizing Asset Import... +[ DONE ] reimport + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Executing post-reimport operations... +[ DONE ] reimport + +[ 0% ] loading_editor_layout | Started Loading editor (5 steps) +[ 0% ] loading_editor_layout | Loading editor layout... +[ 16% ] loading_editor_layout | Loading docks... +[ 33% ] loading_editor_layout | Reopening scenes... +[ 50% ] loading_editor_layout | Loading central editor layout... +[ 66% ] loading_editor_layout | Loading plugin window layout... +[ 83% ] loading_editor_layout | Editor layout ready. +[ DONE ] loading_editor_layout + +[MCPServer] stopped +[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot diff --git a/tmp/console_layout.cjs b/tmp/console_layout.cjs new file mode 100644 index 0000000..d206881 --- /dev/null +++ b/tmp/console_layout.cjs @@ -0,0 +1,2 @@ +const fs=require('fs');let p='scripts/game/flight_hud.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');s=s.replace('_cockpit.scale = Vector2.ONE * 0.85\n\t_cockpit.size = Vector2(minf(850.0, ($HUDRoot.size.x - 24) / 0.85), 120)\n\t_cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12)','var cockpit_scale := minf(0.85, ($HUDRoot.size.x - 24.0) / 850.0)\n\t_cockpit.scale = Vector2.ONE * cockpit_scale\n\t_cockpit.size = Vector2(850, 144)\n\t_cockpit.position = Vector2(($HUDRoot.size.x - 850.0 * cockpit_scale) * 0.5, $HUDRoot.size.y - 144.0 * cockpit_scale - 12)');fs.writeFileSync(p,s); +p='scripts/ui/enemy_drawer.gd';s=fs.readFileSync(p,'utf8').replace('"font_size", 9','"font_size", 8');s=s.replace('_label.name = "EnemyDetails"','_label.name = "EnemyDetails"\n\t_label.add_theme_font_override("font", ThemeDB.fallback_font)');s=s.replace('DamageTypes.describe(profile["absorption"])','"K %.1f%% · E %.1f%% · R %.1f%%" % [profile["absorption"].x, profile["absorption"].y, profile["absorption"].z]');fs.writeFileSync(p,s); diff --git a/tmp/console_review-errors.log b/tmp/console_review-errors.log new file mode 100644 index 0000000..dd33cf9 --- /dev/null +++ b/tmp/console_review-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/captain_ring_review.gd:7) diff --git a/tmp/console_review.log b/tmp/console_review.log new file mode 100644 index 0000000..83bdac2 --- /dev/null +++ b/tmp/console_review.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +CAPTAIN_RING_REVIEW_OK: compact panel, live XP and credits, equipment click, level-up access diff --git a/tmp/enlarge_captain.cjs b/tmp/enlarge_captain.cjs new file mode 100644 index 0000000..b12cef7 --- /dev/null +++ b/tmp/enlarge_captain.cjs @@ -0,0 +1,3 @@ +const fs=require('fs');let p='scripts/ui/captain_panel.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n');s=s.replace('signal equipment_requested','signal equipment_requested\n\nconst PANEL_SCALE := 1.3');s=s.replace('control.position = rect.position','control.position = rect.position * PANEL_SCALE').replace('control.size = rect.size','control.size = rect.size * PANEL_SCALE');s=s.replace('custom_minimum_size = Vector2(244, 72)','custom_minimum_size = Vector2(244, 72) * PANEL_SCALE');s=s.replace('draw_circle(Vector2(36, 36), 28,','draw_circle(Vector2(36, 36) * PANEL_SCALE, 28 * PANEL_SCALE,');s=s.replace('draw_style_box(glass, Rect2(73, 17, 160, 36))','draw_style_box(glass, Rect2(Vector2(73, 17) * PANEL_SCALE, Vector2(160, 36) * PANEL_SCALE))');fs.writeFileSync(p,s); +p='scripts/game/flight_hud.gd';s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n').replace('_captain_panel.size = Vector2(244, _captain_panel.get_combined_minimum_size().y)','_captain_panel.size = _captain_panel.get_combined_minimum_size()');fs.writeFileSync(p,s); +p='scenes/ui/captain_panel.tscn';s=fs.readFileSync(p,'utf8').replace('Vector2(244, 72)','Vector2(317.2, 93.6)');fs.writeFileSync(p,s); diff --git a/tmp/frame_import-errors.log b/tmp/frame_import-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/frame_import.log b/tmp/frame_import.log new file mode 100644 index 0000000..0d8ea7b --- /dev/null +++ b/tmp/frame_import.log @@ -0,0 +1,39 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[ 0% ] first_scan_filesystem | Started Project initialization (5 steps) +[ 0% ] first_scan_filesystem | Scanning file structure... +[ 16% ] first_scan_filesystem | Loading global class names... +[ 33% ] first_scan_filesystem | Verifying GDExtensions... +[ 50% ] first_scan_filesystem | Creating autoload scripts... +[ 66% ] first_scan_filesystem | Initializing plugins... +Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com +[MCPExtensions] Hot-reload watcher active +[MCPServer] port: scanning 6550-6560 (default) +[MCPServer] session token written to user://addons/godot_mcp_toolkit/project_instance_32cc2271ac67/mcp_token +[MCPServer] listening on 127.0.0.1:6551 +[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551 +[ 83% ] first_scan_filesystem | Starting file scan... +[ DONE ] first_scan_filesystem + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Preparing files to reimport... +[ 0% ] reimport | Executing pre-reimport operations... +[ 0% ] reimport | ship_status_frame.png +[ 50% ] reimport | Finalizing Asset Import... +[ DONE ] reimport + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Executing post-reimport operations... +[ DONE ] reimport + +[ 0% ] loading_editor_layout | Started Loading editor (5 steps) +[ 0% ] loading_editor_layout | Loading editor layout... +[ 16% ] loading_editor_layout | Loading docks... +[ 33% ] loading_editor_layout | Reopening scenes... +[ 50% ] loading_editor_layout | Loading central editor layout... +[ 66% ] loading_editor_layout | Loading plugin window layout... +[ 83% ] loading_editor_layout | Editor layout ready. +[ DONE ] loading_editor_layout + +[MCPServer] stopped +[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot diff --git a/tmp/gamma_range-errors.log b/tmp/gamma_range-errors.log new file mode 100644 index 0000000..fdca118 --- /dev/null +++ b/tmp/gamma_range-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tests/levels/hard_balance_test.gd:52) diff --git a/tmp/gamma_range.log b/tmp/gamma_range.log new file mode 100644 index 0000000..7a07837 --- /dev/null +++ b/tmp/gamma_range.log @@ -0,0 +1,6 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +HARD_BALANCE_TEST_OK: levels 1-120, 60/61 transition, absorption, all tiers, boss multipliers and intro diff --git a/tmp/ring_import-errors.log b/tmp/ring_import-errors.log new file mode 100644 index 0000000..e69de29 diff --git a/tmp/ring_import.log b/tmp/ring_import.log new file mode 100644 index 0000000..aa88c37 --- /dev/null +++ b/tmp/ring_import.log @@ -0,0 +1,39 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org + +[ 0% ] first_scan_filesystem | Started Project initialization (5 steps) +[ 0% ] first_scan_filesystem | Scanning file structure... +[ 16% ] first_scan_filesystem | Loading global class names... +[ 33% ] first_scan_filesystem | Verifying GDExtensions... +[ 50% ] first_scan_filesystem | Creating autoload scripts... +[ 66% ] first_scan_filesystem | Initializing plugins... +Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com +[MCPExtensions] Hot-reload watcher active +[MCPServer] port: scanning 6550-6560 (default) +[MCPServer] session token written to user://addons/godot_mcp_toolkit/project_instance_32cc2271ac67/mcp_token +[MCPServer] listening on 127.0.0.1:6551 +[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551 +[ 83% ] first_scan_filesystem | Starting file scan... +[ DONE ] first_scan_filesystem + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Preparing files to reimport... +[ 0% ] reimport | Executing pre-reimport operations... +[ 0% ] reimport | ship_ring_bars.png +[ 50% ] reimport | Finalizing Asset Import... +[ DONE ] reimport + +[ 0% ] reimport | Started (Re)Importing Assets (1 steps) +[ 0% ] reimport | Executing post-reimport operations... +[ DONE ] reimport + +[ 0% ] loading_editor_layout | Started Loading editor (5 steps) +[ 0% ] loading_editor_layout | Loading editor layout... +[ 16% ] loading_editor_layout | Loading docks... +[ 33% ] loading_editor_layout | Reopening scenes... +[ 50% ] loading_editor_layout | Loading central editor layout... +[ 66% ] loading_editor_layout | Loading plugin window layout... +[ 83% ] loading_editor_layout | Editor layout ready. +[ DONE ] loading_editor_layout + +[MCPServer] stopped +[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot diff --git a/tmp/ring_review-errors.log b/tmp/ring_review-errors.log new file mode 100644 index 0000000..97e9b30 --- /dev/null +++ b/tmp/ring_review-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/ship_frame_review.gd:5) diff --git a/tmp/ring_review.log b/tmp/ring_review.log new file mode 100644 index 0000000..7a43c30 --- /dev/null +++ b/tmp/ring_review.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6571 +[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot +SHIP_FRAME_REVIEW_OK diff --git a/tmp/ship_frame_review-errors.log b/tmp/ship_frame_review-errors.log new file mode 100644 index 0000000..97e9b30 --- /dev/null +++ b/tmp/ship_frame_review-errors.log @@ -0,0 +1,4 @@ +WARNING: Camera2D overridden to physics process mode due to use of physics interpolation. + at: _update_process_callback (scene/2d/camera_2d.cpp:88) + GDScript backtrace (most recent call first): + [0] _ready (res://tmp/ship_frame_review.gd:5) diff --git a/tmp/ship_frame_review.gd b/tmp/ship_frame_review.gd new file mode 100644 index 0000000..5e9ff21 --- /dev/null +++ b/tmp/ship_frame_review.gd @@ -0,0 +1,20 @@ +extends Node +func _ready() -> void: + GameState.start_new_run() + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + game.set_physics_process(false) + game.player.set_physics_process(false) + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) + for frame in 12: await get_tree().process_frame + var panel = game.get_node("HUD")._sidebar_toggle + assert(panel.size.x == 221 and panel.size.y == 71.5) + assert(panel._frame_texture != null) + game.player.hull = game.player.max_hull * 0.65 + game.player.shields = game.player.max_shields * 0.4 + for frame in 20: await get_tree().process_frame + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/ship_status_frame_review.png") + get_viewport().get_texture().get_image().get_region(Rect2i(panel.get_global_rect().grow(4))).save_png("res://artifacts/ship_ring_panel.png") + print("SHIP_FRAME_REVIEW_OK") + get_tree().quit() diff --git a/tmp/ship_frame_review.gd.uid b/tmp/ship_frame_review.gd.uid new file mode 100644 index 0000000..c49643b --- /dev/null +++ b/tmp/ship_frame_review.gd.uid @@ -0,0 +1 @@ +uid://bxksexngdnhr2 diff --git a/tmp/ship_frame_review.log b/tmp/ship_frame_review.log new file mode 100644 index 0000000..d39e4d7 --- /dev/null +++ b/tmp/ship_frame_review.log @@ -0,0 +1,7 @@ +Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org +Vulkan 1.4.341 - Forward+ - Using Device #0: NVIDIA - NVIDIA GeForce RTX 4070 SUPER + +[MCPRuntimeServer] port: scanning 6570-6585 (default) +[MCPRuntimeServer] listening on 127.0.0.1:6570 +[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot +SHIP_FRAME_REVIEW_OK diff --git a/tmp/ship_frame_review.tscn b/tmp/ship_frame_review.tscn new file mode 100644 index 0000000..8914607 --- /dev/null +++ b/tmp/ship_frame_review.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tmp/ship_frame_review.gd" id="1"] +[node name="Review" type="Node"] +script = ExtResource("1") diff --git a/tmp/update_ring.cjs b/tmp/update_ring.cjs new file mode 100644 index 0000000..0e158f9 --- /dev/null +++ b/tmp/update_ring.cjs @@ -0,0 +1,29 @@ +const fs=require('fs');const p='scripts/ui/ship_profile.gd';let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n'); +s=s.replace('var _ship_name := ""\n','').replace('\t_ship_name = ship["name"]\n',''); +s=s.replace('ship_status_frame.png','ship_ring_bars.png').replace(/\t# Exclude[^\n]*\n\t_frame_region = Rect2\(12, 90, 2170, 534\)/,'\t_frame_region = Rect2(Vector2.ZERO, _frame_texture.get_size())'); +const start=s.indexOf('\tvar accent :=',s.indexOf('func _draw()'));const end=s.indexOf('\nfunc _bar(',start); +s=s.slice(0,start)+`\tvar portrait := Vector2(185, 35.5) +\tdraw_circle(portrait, 26, Color("0a141b66")) +\tif _texture != null: +\t\tvar dimensions := _texture.get_size() +\t\tvar extent := dimensions * (44.0 / maxf(dimensions.x, dimensions.y)) +\t\tdraw_texture_rect(_texture, Rect2(portrait - extent * 0.5, extent), false) +\t_bar(Rect2(12, 15, 126, 7), player.hull, player.max_hull, _display.x, Color("e88972"), "KADŁUB") +\t_bar(Rect2(12, 32, 126, 7), player.shields, player.max_shields, _display.y, Color("79bde5"), "TARCZE") +\t_bar(Rect2(12, 49, 126, 7), player.energy, player.max_energy, _display.z, Color("87cfb1"), "ENERGIA") +\tif _frame_texture != null: +\t\tdraw_texture_rect_region(_frame_texture, Rect2(Vector2.ZERO, size), _frame_region, Color(1, 1, 1, 1.0 if is_hovered() else 0.88)) +\t_bar_caption(Vector2(13, 21), player.hull, player.max_hull, "KADŁUB") +\t_bar_caption(Vector2(13, 38), player.shields, player.max_shields, "TARCZE") +\t_bar_caption(Vector2(13, 55), player.energy, player.max_energy, "ENERGIA") + +func _bar_caption(point: Vector2, value: float, maximum: float, caption: String) -> void: +\tvar font := ThemeDB.fallback_font +\tvar values := "%.0f / %.0f" % [value, maximum] +\tdraw_string_outline(font, point, caption, HORIZONTAL_ALIGNMENT_LEFT, 58, 7, 2, Color("071117")) +\tdraw_string_outline(font, point, values, HORIZONTAL_ALIGNMENT_RIGHT, 123, 7, 2, Color("071117")) +\tdraw_string(font, point, caption, HORIZONTAL_ALIGNMENT_LEFT, 58, 7, TEXT) +\tdraw_string(font, point, values, HORIZONTAL_ALIGNMENT_RIGHT, 123, 7, TEXT) +`+s.slice(end); +s=s.replace(/\tvar font := ThemeDB.fallback_font\n\tdraw_string\(font, rect.position[^\n]*\n\tdraw_string\(font, rect.position[^\n]*\n/,''); +s=s.replace('color: Color, caption: String) -> void:', 'color: Color, _caption: String) -> void:');fs.writeFileSync(p,s); diff --git a/tmp/update_ship_frame.cjs b/tmp/update_ship_frame.cjs new file mode 100644 index 0000000..8b44d51 --- /dev/null +++ b/tmp/update_ship_frame.cjs @@ -0,0 +1,12 @@ +const fs = require('fs'); +const p='scripts/ui/ship_profile.gd'; +let s=fs.readFileSync(p,'utf8').replace(/\r\n/g,'\n'); +s=s.replace('var _ship_name := ""','var _frame_texture: Texture2D\nvar _frame_region := Rect2()\nvar _ship_name := ""'); +s=s.replace(/\tvar frame := preload\("res:\/\/scripts\/ui\/ornamental_frame.gd"\).new\(\)\n\tframe.corner_size = 11\n\tframe.opacity = 0.9\n\tadd_child\(frame\)/,'\t_frame_texture = load("res://assets/ui/frames/ship_status_frame.png") as Texture2D\n\tvar frame_image := _frame_texture.get_image()\n\tif frame_image.is_compressed(): frame_image.decompress()\n\t_frame_region = Rect2(frame_image.get_used_rect())'); +s=s.replace('box.bg_color = Color("101d247a")','box.bg_color = Color("0b18254d")'); +s=s.replace('box.set_border_width_all(1)','box.set_border_width_all(0)'); +s=s.replace('box.shadow_size = 5','box.shadow_size = 2'); +s=s.replace('draw_circle(portrait, 21, Color("0a141b"))','draw_circle(portrait, 21, Color("0a141b66"))'); +s=s.replace('draw_arc(portrait, 24, -PI * 0.85, PI * 0.85, 48, accent, 1.5, true)','draw_arc(portrait, 23, -PI * 0.85, PI * 0.85, 48, accent, 1.0, true)'); +s=s.replace('\nfunc _bar(', '\n\tif _frame_texture != null:\n\t\tdraw_texture_rect_region(_frame_texture, Rect2(Vector2.ZERO, size), _frame_region, Color(1, 1, 1, 1.0 if is_hovered() else 0.88))\n\nfunc _bar('); +fs.writeFileSync(p,s);