diff --git a/artifacts/dark_frigate_hangar.png b/artifacts/dark_frigate_hangar.png new file mode 100644 index 0000000..2227e9b Binary files /dev/null and b/artifacts/dark_frigate_hangar.png differ diff --git a/artifacts/dark_frigate_hangar.png.import b/artifacts/dark_frigate_hangar.png.import new file mode 100644 index 0000000..8125656 --- /dev/null +++ b/artifacts/dark_frigate_hangar.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqi268nvnmynw" +path="res://.godot/imported/dark_frigate_hangar.png-2975452b2076130e4444c05f62753646.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/dark_frigate_hangar.png" +dest_files=["res://.godot/imported/dark_frigate_hangar.png-2975452b2076130e4444c05f62753646.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/dark_frigate_space.png b/artifacts/dark_frigate_space.png new file mode 100644 index 0000000..3faab30 Binary files /dev/null and b/artifacts/dark_frigate_space.png differ diff --git a/artifacts/dark_frigate_space.png.import b/artifacts/dark_frigate_space.png.import new file mode 100644 index 0000000..4fc1ec5 --- /dev/null +++ b/artifacts/dark_frigate_space.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwjqsir1gt880" +path="res://.godot/imported/dark_frigate_space.png-91c7f305969e0f923f8356ef49e68927.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/dark_frigate_space.png" +dest_files=["res://.godot/imported/dark_frigate_space.png-91c7f305969e0f923f8356ef49e68927.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/epic_frigate_hangar.png b/artifacts/epic_frigate_hangar.png new file mode 100644 index 0000000..1fe6021 Binary files /dev/null and b/artifacts/epic_frigate_hangar.png differ diff --git a/artifacts/epic_frigate_hangar.png.import b/artifacts/epic_frigate_hangar.png.import new file mode 100644 index 0000000..a692bc6 --- /dev/null +++ b/artifacts/epic_frigate_hangar.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rcv4mxkkddao" +path="res://.godot/imported/epic_frigate_hangar.png-683bcc7e4eeb2e81e29cc4385a7115c3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/epic_frigate_hangar.png" +dest_files=["res://.godot/imported/epic_frigate_hangar.png-683bcc7e4eeb2e81e29cc4385a7115c3.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/epic_frigate_space.png b/artifacts/epic_frigate_space.png new file mode 100644 index 0000000..6ca35d4 Binary files /dev/null and b/artifacts/epic_frigate_space.png differ diff --git a/artifacts/epic_frigate_space.png.import b/artifacts/epic_frigate_space.png.import new file mode 100644 index 0000000..934b760 --- /dev/null +++ b/artifacts/epic_frigate_space.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bhtksffboha2p" +path="res://.godot/imported/epic_frigate_space.png-548b6092b1baa3c793dbd0ae169a5e2b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/epic_frigate_space.png" +dest_files=["res://.godot/imported/epic_frigate_space.png-548b6092b1baa3c793dbd0ae169a5e2b.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/event_barter.png.import b/artifacts/event_barter.png.import new file mode 100644 index 0000000..059fa5e --- /dev/null +++ b/artifacts/event_barter.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vybjw0wgt4gu" +path="res://.godot/imported/event_barter.png-1d755fd75326c540f0ef67d02cc52e9a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_barter.png" +dest_files=["res://.godot/imported/event_barter.png-1d755fd75326c540f0ef67d02cc52e9a.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/event_blind_cache.png.import b/artifacts/event_blind_cache.png.import new file mode 100644 index 0000000..239e931 --- /dev/null +++ b/artifacts/event_blind_cache.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rrri8t5xy5x" +path="res://.godot/imported/event_blind_cache.png-9b40fe1d0f2e5c42b5efdafd55f6f2c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_blind_cache.png" +dest_files=["res://.godot/imported/event_blind_cache.png-9b40fe1d0f2e5c42b5efdafd55f6f2c5.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/event_collector.png.import b/artifacts/event_collector.png.import new file mode 100644 index 0000000..7e2f989 --- /dev/null +++ b/artifacts/event_collector.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbg2mjo4ptcp5" +path="res://.godot/imported/event_collector.png-14f70877fe61d5870bc5ecc002e7b97d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_collector.png" +dest_files=["res://.godot/imported/event_collector.png-14f70877fe61d5870bc5ecc002e7b97d.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/event_evacuation.png.import b/artifacts/event_evacuation.png.import new file mode 100644 index 0000000..0b82d56 --- /dev/null +++ b/artifacts/event_evacuation.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b11gqnq6h3gbm" +path="res://.godot/imported/event_evacuation.png-bb2ae55645dcef28ae923a91cdc11158.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_evacuation.png" +dest_files=["res://.godot/imported/event_evacuation.png-bb2ae55645dcef28ae923a91cdc11158.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/event_evacuation_stage2.png.import b/artifacts/event_evacuation_stage2.png.import new file mode 100644 index 0000000..d896b68 --- /dev/null +++ b/artifacts/event_evacuation_stage2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dtp7idnbvo16j" +path="res://.godot/imported/event_evacuation_stage2.png-481d268889b9481c1a93efb54239786b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_evacuation_stage2.png" +dest_files=["res://.godot/imported/event_evacuation_stage2.png-481d268889b9481c1a93efb54239786b.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/event_prototype.png.import b/artifacts/event_prototype.png.import new file mode 100644 index 0000000..fe413f4 --- /dev/null +++ b/artifacts/event_prototype.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwhnqeaookjjw" +path="res://.godot/imported/event_prototype.png-ff75fa404f9cb9fce94f3c6064980760.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_prototype.png" +dest_files=["res://.godot/imported/event_prototype.png-ff75fa404f9cb9fce94f3c6064980760.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/event_rescue.png.import b/artifacts/event_rescue.png.import new file mode 100644 index 0000000..0e400a8 --- /dev/null +++ b/artifacts/event_rescue.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bmlr36jdopaxi" +path="res://.godot/imported/event_rescue.png-ba48ac96d0f8b8ff0bb9904089ac69b5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_rescue.png" +dest_files=["res://.godot/imported/event_rescue.png-ba48ac96d0f8b8ff0bb9904089ac69b5.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/event_safe_bet.png.import b/artifacts/event_safe_bet.png.import new file mode 100644 index 0000000..610fe68 --- /dev/null +++ b/artifacts/event_safe_bet.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcrt81uxyto0e" +path="res://.godot/imported/event_safe_bet.png-080771b09b7a99b03576b0523e80be31.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_safe_bet.png" +dest_files=["res://.godot/imported/event_safe_bet.png-080771b09b7a99b03576b0523e80be31.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/event_scan_cache.png.import b/artifacts/event_scan_cache.png.import new file mode 100644 index 0000000..d5624ff --- /dev/null +++ b/artifacts/event_scan_cache.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwd4vpcj841hv" +path="res://.godot/imported/event_scan_cache.png-fba33af48e7037a9157835055609cd98.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_scan_cache.png" +dest_files=["res://.godot/imported/event_scan_cache.png-fba33af48e7037a9157835055609cd98.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/event_scan_result.png.import b/artifacts/event_scan_result.png.import new file mode 100644 index 0000000..d034df1 --- /dev/null +++ b/artifacts/event_scan_result.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://diqy1xtpwv3sn" +path="res://.godot/imported/event_scan_result.png-907755d8d2192a1e40e2624c576fee7e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_scan_result.png" +dest_files=["res://.godot/imported/event_scan_result.png-907755d8d2192a1e40e2624c576fee7e.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/event_service.png.import b/artifacts/event_service.png.import new file mode 100644 index 0000000..9f4af1a --- /dev/null +++ b/artifacts/event_service.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2t6hkt3pggpd" +path="res://.godot/imported/event_service.png-f6e823641432ef4be08adc6d2d77ce53.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_service.png" +dest_files=["res://.godot/imported/event_service.png-f6e823641432ef4be08adc6d2d77ce53.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/event_trader.png.import b/artifacts/event_trader.png.import new file mode 100644 index 0000000..a16f59f --- /dev/null +++ b/artifacts/event_trader.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c6721reekikk5" +path="res://.godot/imported/event_trader.png-2dc992f39d36b2e9a09f467bc21147bd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/event_trader.png" +dest_files=["res://.godot/imported/event_trader.png-2dc992f39d36b2e9a09f467bc21147bd.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/events_overview.png.import b/artifacts/events_overview.png.import new file mode 100644 index 0000000..5a59ad1 --- /dev/null +++ b/artifacts/events_overview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cuqm8oj4vyeye" +path="res://.godot/imported/events_overview.png-1a5f76349ee02c369671b0409c116a12.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/events_overview.png" +dest_files=["res://.godot/imported/events_overview.png-1a5f76349ee02c369671b0409c116a12.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/freighter_interior_built.png b/artifacts/freighter_interior_built.png new file mode 100644 index 0000000..74904a9 Binary files /dev/null and b/artifacts/freighter_interior_built.png differ diff --git a/artifacts/freighter_interior_built.png.import b/artifacts/freighter_interior_built.png.import new file mode 100644 index 0000000..a8e7ad9 --- /dev/null +++ b/artifacts/freighter_interior_built.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ba2xuvaj3tad8" +path="res://.godot/imported/freighter_interior_built.png-28d80ac7f3bb31c133990681b058cdef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_built.png" +dest_files=["res://.godot/imported/freighter_interior_built.png-28d80ac7f3bb31c133990681b058cdef.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/freighter_interior_hangar.png b/artifacts/freighter_interior_hangar.png new file mode 100644 index 0000000..5aeb4ce Binary files /dev/null and b/artifacts/freighter_interior_hangar.png differ diff --git a/artifacts/freighter_interior_hangar.png.import b/artifacts/freighter_interior_hangar.png.import new file mode 100644 index 0000000..557f515 --- /dev/null +++ b/artifacts/freighter_interior_hangar.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxc1n5g1m4a8r" +path="res://.godot/imported/freighter_interior_hangar.png-22358b481efbde5944ba70fbaaea5c02.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_hangar.png" +dest_files=["res://.godot/imported/freighter_interior_hangar.png-22358b481efbde5944ba70fbaaea5c02.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/freighter_interior_overview.png b/artifacts/freighter_interior_overview.png new file mode 100644 index 0000000..b81c8c3 Binary files /dev/null and b/artifacts/freighter_interior_overview.png differ diff --git a/artifacts/freighter_interior_overview.png.import b/artifacts/freighter_interior_overview.png.import new file mode 100644 index 0000000..e790f10 --- /dev/null +++ b/artifacts/freighter_interior_overview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://coir8x8nrkt0" +path="res://.godot/imported/freighter_interior_overview.png-06eddb85465bbe7e7b91db8c9de6aef6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_overview.png" +dest_files=["res://.godot/imported/freighter_interior_overview.png-06eddb85465bbe7e7b91db8c9de6aef6.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/freighter_interior_renovation.png b/artifacts/freighter_interior_renovation.png new file mode 100644 index 0000000..51c6e3c Binary files /dev/null and b/artifacts/freighter_interior_renovation.png differ diff --git a/artifacts/freighter_interior_renovation.png.import b/artifacts/freighter_interior_renovation.png.import new file mode 100644 index 0000000..172e8f2 --- /dev/null +++ b/artifacts/freighter_interior_renovation.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://pptkvmn1xrtb" +path="res://.godot/imported/freighter_interior_renovation.png-88019c07842e982be7fd871a4b84f770.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_renovation.png" +dest_files=["res://.godot/imported/freighter_interior_renovation.png-88019c07842e982be7fd871a4b84f770.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/freighter_interior_second_ship.png b/artifacts/freighter_interior_second_ship.png new file mode 100644 index 0000000..ad95d2d Binary files /dev/null and b/artifacts/freighter_interior_second_ship.png differ diff --git a/artifacts/freighter_interior_second_ship.png.import b/artifacts/freighter_interior_second_ship.png.import new file mode 100644 index 0000000..4adc896 --- /dev/null +++ b/artifacts/freighter_interior_second_ship.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://md2dnu0gpbit" +path="res://.godot/imported/freighter_interior_second_ship.png-265c90a153b12d9723800f70508b0e0f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_second_ship.png" +dest_files=["res://.godot/imported/freighter_interior_second_ship.png-265c90a153b12d9723800f70508b0e0f.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/freighter_interior_workshop.png b/artifacts/freighter_interior_workshop.png new file mode 100644 index 0000000..5b05c8a Binary files /dev/null and b/artifacts/freighter_interior_workshop.png differ diff --git a/artifacts/freighter_interior_workshop.png.import b/artifacts/freighter_interior_workshop.png.import new file mode 100644 index 0000000..87646cf --- /dev/null +++ b/artifacts/freighter_interior_workshop.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://byglwn0t674b5" +path="res://.godot/imported/freighter_interior_workshop.png-c9a542fd5df94bdececaf1dc9464ac21.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_interior_workshop.png" +dest_files=["res://.godot/imported/freighter_interior_workshop.png-c9a542fd5df94bdececaf1dc9464ac21.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/freighter_prompt_fixed.png b/artifacts/freighter_prompt_fixed.png index b90ba70..c10096c 100644 Binary files a/artifacts/freighter_prompt_fixed.png and b/artifacts/freighter_prompt_fixed.png differ diff --git a/artifacts/freighter_storage.png b/artifacts/freighter_storage.png new file mode 100644 index 0000000..e09d3e5 Binary files /dev/null and b/artifacts/freighter_storage.png differ diff --git a/artifacts/freighter_storage.png.import b/artifacts/freighter_storage.png.import new file mode 100644 index 0000000..991fad1 --- /dev/null +++ b/artifacts/freighter_storage.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cs0qup14ambby" +path="res://.godot/imported/freighter_storage.png-24f030c2d6ffcd22838303f7622437c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/freighter_storage.png" +dest_files=["res://.godot/imported/freighter_storage.png-24f030c2d6ffcd22838303f7622437c5.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 new file mode 100644 index 0000000..738087d Binary files /dev/null and b/artifacts/hangar_slot_unlock.png differ diff --git a/artifacts/hangar_slot_unlock.png.import b/artifacts/hangar_slot_unlock.png.import new file mode 100644 index 0000000..d25f67e --- /dev/null +++ b/artifacts/hangar_slot_unlock.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://xhgcbcl2lng1" +path="res://.godot/imported/hangar_slot_unlock.png-aa8b20c276a8099ff7788bc522fb225c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hangar_slot_unlock.png" +dest_files=["res://.godot/imported/hangar_slot_unlock.png-aa8b20c276a8099ff7788bc522fb225c.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/hard_event_barter.png.import b/artifacts/hard_event_barter.png.import new file mode 100644 index 0000000..72a5155 --- /dev/null +++ b/artifacts/hard_event_barter.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqxtqwg6jnhfg" +path="res://.godot/imported/hard_event_barter.png-57397c08b6bf25cf302f41890ab3d2fb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_barter.png" +dest_files=["res://.godot/imported/hard_event_barter.png-57397c08b6bf25cf302f41890ab3d2fb.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/hard_event_blind_cache.png.import b/artifacts/hard_event_blind_cache.png.import new file mode 100644 index 0000000..549bd70 --- /dev/null +++ b/artifacts/hard_event_blind_cache.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1pvdm0m3chib" +path="res://.godot/imported/hard_event_blind_cache.png-8f6cb8b3389419f3ae0a5f77d62aebe0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_blind_cache.png" +dest_files=["res://.godot/imported/hard_event_blind_cache.png-8f6cb8b3389419f3ae0a5f77d62aebe0.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/hard_event_collector.png.import b/artifacts/hard_event_collector.png.import new file mode 100644 index 0000000..17598ab --- /dev/null +++ b/artifacts/hard_event_collector.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0a115rgcbdth" +path="res://.godot/imported/hard_event_collector.png-24e576898684fd8aa4e087d2494c7543.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_collector.png" +dest_files=["res://.godot/imported/hard_event_collector.png-24e576898684fd8aa4e087d2494c7543.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/hard_event_evacuation.png.import b/artifacts/hard_event_evacuation.png.import new file mode 100644 index 0000000..91e0d54 --- /dev/null +++ b/artifacts/hard_event_evacuation.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctqfyo1gquglt" +path="res://.godot/imported/hard_event_evacuation.png-a62ae1ddeda6ce8553eb4ea5cf1a1478.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_evacuation.png" +dest_files=["res://.godot/imported/hard_event_evacuation.png-a62ae1ddeda6ce8553eb4ea5cf1a1478.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/hard_event_evacuation_stage2.png.import b/artifacts/hard_event_evacuation_stage2.png.import new file mode 100644 index 0000000..e439b40 --- /dev/null +++ b/artifacts/hard_event_evacuation_stage2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cd1vwk13mgl6g" +path="res://.godot/imported/hard_event_evacuation_stage2.png-8f9425a2949f7b5d52f49033746d0b73.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_evacuation_stage2.png" +dest_files=["res://.godot/imported/hard_event_evacuation_stage2.png-8f9425a2949f7b5d52f49033746d0b73.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/hard_event_prototype.png.import b/artifacts/hard_event_prototype.png.import new file mode 100644 index 0000000..5828183 --- /dev/null +++ b/artifacts/hard_event_prototype.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1t0sactbswnn" +path="res://.godot/imported/hard_event_prototype.png-d58c539e319785cae908a58d1357815b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_prototype.png" +dest_files=["res://.godot/imported/hard_event_prototype.png-d58c539e319785cae908a58d1357815b.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/hard_event_rescue.png.import b/artifacts/hard_event_rescue.png.import new file mode 100644 index 0000000..eaed4bd --- /dev/null +++ b/artifacts/hard_event_rescue.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpp1mivi2yf4b" +path="res://.godot/imported/hard_event_rescue.png-8fa5bd4c8f78af9fba281eb5629c338b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_rescue.png" +dest_files=["res://.godot/imported/hard_event_rescue.png-8fa5bd4c8f78af9fba281eb5629c338b.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/hard_event_safe_bet.png.import b/artifacts/hard_event_safe_bet.png.import new file mode 100644 index 0000000..8a4c49b --- /dev/null +++ b/artifacts/hard_event_safe_bet.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bmrans3w8k13k" +path="res://.godot/imported/hard_event_safe_bet.png-9dc4cacb2f6bddb3f7ad99e7b7430271.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_safe_bet.png" +dest_files=["res://.godot/imported/hard_event_safe_bet.png-9dc4cacb2f6bddb3f7ad99e7b7430271.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/hard_event_scan_cache.png.import b/artifacts/hard_event_scan_cache.png.import new file mode 100644 index 0000000..51ce76c --- /dev/null +++ b/artifacts/hard_event_scan_cache.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ee6b45j1mems" +path="res://.godot/imported/hard_event_scan_cache.png-657f606de2f0b85eb1528fd016b22754.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_scan_cache.png" +dest_files=["res://.godot/imported/hard_event_scan_cache.png-657f606de2f0b85eb1528fd016b22754.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/hard_event_scan_result.png.import b/artifacts/hard_event_scan_result.png.import new file mode 100644 index 0000000..650b241 --- /dev/null +++ b/artifacts/hard_event_scan_result.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://btbhwnvilyjmp" +path="res://.godot/imported/hard_event_scan_result.png-da9878457a0bdd5a9721a208d30f101f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_scan_result.png" +dest_files=["res://.godot/imported/hard_event_scan_result.png-da9878457a0bdd5a9721a208d30f101f.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/hard_event_service.png.import b/artifacts/hard_event_service.png.import new file mode 100644 index 0000000..20f5f55 --- /dev/null +++ b/artifacts/hard_event_service.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caqf4iumxumrw" +path="res://.godot/imported/hard_event_service.png-31664c1c141099193f1019a7f904bbf4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_service.png" +dest_files=["res://.godot/imported/hard_event_service.png-31664c1c141099193f1019a7f904bbf4.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/hard_event_trader.png.import b/artifacts/hard_event_trader.png.import new file mode 100644 index 0000000..5cc6356 --- /dev/null +++ b/artifacts/hard_event_trader.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkchxl8dgq8li" +path="res://.godot/imported/hard_event_trader.png-39a8d965902d79ea2a31297c9decc4ad.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_event_trader.png" +dest_files=["res://.godot/imported/hard_event_trader.png-39a8d965902d79ea2a31297c9decc4ad.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/hard_events_overview.png.import b/artifacts/hard_events_overview.png.import new file mode 100644 index 0000000..e0e6af8 --- /dev/null +++ b/artifacts/hard_events_overview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djnswywnri7n6" +path="res://.godot/imported/hard_events_overview.png-cbc9d1fb132a2dedb615d05c9bdf97de.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/hard_events_overview.png" +dest_files=["res://.godot/imported/hard_events_overview.png-cbc9d1fb132a2dedb615d05c9bdf97de.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/planet_scan_stats.png b/artifacts/planet_scan_stats.png index 2e05faa..8afb92e 100644 Binary files a/artifacts/planet_scan_stats.png and b/artifacts/planet_scan_stats.png differ diff --git a/artifacts/planet_services_preview.png b/artifacts/planet_services_preview.png index 199d85a..6b42af5 100644 Binary files a/artifacts/planet_services_preview.png and b/artifacts/planet_services_preview.png differ diff --git a/artifacts/surface_atmosphere_before.png b/artifacts/surface_atmosphere_before.png new file mode 100644 index 0000000..d391b96 Binary files /dev/null and b/artifacts/surface_atmosphere_before.png differ diff --git a/artifacts/surface_atmosphere_before.png.import b/artifacts/surface_atmosphere_before.png.import new file mode 100644 index 0000000..bb2d725 --- /dev/null +++ b/artifacts/surface_atmosphere_before.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cv2xb6a1tm68y" +path="res://.godot/imported/surface_atmosphere_before.png-067972459cc4392eb2e3de6476bb5e76.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/surface_atmosphere_before.png" +dest_files=["res://.godot/imported/surface_atmosphere_before.png-067972459cc4392eb2e3de6476bb5e76.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/surface_atmosphere_clouds.png b/artifacts/surface_atmosphere_clouds.png new file mode 100644 index 0000000..824d292 Binary files /dev/null and b/artifacts/surface_atmosphere_clouds.png differ diff --git a/artifacts/surface_atmosphere_clouds.png.import b/artifacts/surface_atmosphere_clouds.png.import new file mode 100644 index 0000000..df716a3 --- /dev/null +++ b/artifacts/surface_atmosphere_clouds.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bqahvlr5vq63q" +path="res://.godot/imported/surface_atmosphere_clouds.png-8c92199665ab1b8d972a18996279b717.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/surface_atmosphere_clouds.png" +dest_files=["res://.godot/imported/surface_atmosphere_clouds.png-8c92199665ab1b8d972a18996279b717.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/surface_atmosphere_mountains.png b/artifacts/surface_atmosphere_mountains.png new file mode 100644 index 0000000..d2c3473 Binary files /dev/null and b/artifacts/surface_atmosphere_mountains.png differ diff --git a/artifacts/surface_atmosphere_mountains.png.import b/artifacts/surface_atmosphere_mountains.png.import new file mode 100644 index 0000000..bef35a0 --- /dev/null +++ b/artifacts/surface_atmosphere_mountains.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ptqi7kdxwgp8" +path="res://.godot/imported/surface_atmosphere_mountains.png-1e105eb85393f3c5c20634bf1115f87a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/surface_atmosphere_mountains.png" +dest_files=["res://.godot/imported/surface_atmosphere_mountains.png-1e105eb85393f3c5c20634bf1115f87a.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/terrain_detail_0.png b/artifacts/terrain_detail_0.png index 7f7d301..12ea5d8 100644 Binary files a/artifacts/terrain_detail_0.png and b/artifacts/terrain_detail_0.png differ diff --git a/artifacts/terrain_detail_1.png b/artifacts/terrain_detail_1.png index 7569bc7..997710f 100644 Binary files a/artifacts/terrain_detail_1.png and b/artifacts/terrain_detail_1.png differ diff --git a/artifacts/terrain_detail_2.png b/artifacts/terrain_detail_2.png index c586589..41c7447 100644 Binary files a/artifacts/terrain_detail_2.png and b/artifacts/terrain_detail_2.png differ diff --git a/artifacts/terrain_detail_3.png b/artifacts/terrain_detail_3.png index 8eeee9c..310c615 100644 Binary files a/artifacts/terrain_detail_3.png and b/artifacts/terrain_detail_3.png differ diff --git a/artifacts/terrain_detail_4.png b/artifacts/terrain_detail_4.png index 187c9b4..ef4f932 100644 Binary files a/artifacts/terrain_detail_4.png and b/artifacts/terrain_detail_4.png differ diff --git a/artifacts/terrain_detail_5.png b/artifacts/terrain_detail_5.png index 9aecf87..e404adc 100644 Binary files a/artifacts/terrain_detail_5.png and b/artifacts/terrain_detail_5.png differ diff --git a/artifacts/terrain_material_variants_final.png b/artifacts/terrain_material_variants_final.png index 1d5a607..a276c9e 100644 Binary files a/artifacts/terrain_material_variants_final.png and b/artifacts/terrain_material_variants_final.png differ diff --git a/artifacts/threat_rescue_150.png.import b/artifacts/threat_rescue_150.png.import new file mode 100644 index 0000000..f31d99d --- /dev/null +++ b/artifacts/threat_rescue_150.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c640jf4q6nxhe" +path="res://.godot/imported/threat_rescue_150.png-7feb997564659651cf189db90026be3d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_rescue_150.png" +dest_files=["res://.godot/imported/threat_rescue_150.png-7feb997564659651cf189db90026be3d.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/threat_scan_150.png.import b/artifacts/threat_scan_150.png.import new file mode 100644 index 0000000..c80a9b6 --- /dev/null +++ b/artifacts/threat_scan_150.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://2ea5ol8geffv" +path="res://.godot/imported/threat_scan_150.png-18fb5d144182b7c26b1bb55c7e00203b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_scan_150.png" +dest_files=["res://.godot/imported/threat_scan_150.png-18fb5d144182b7c26b1bb55c7e00203b.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/threat_scan_l50.png.import b/artifacts/threat_scan_l50.png.import new file mode 100644 index 0000000..451c8b8 --- /dev/null +++ b/artifacts/threat_scan_l50.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmnucmupercxy" +path="res://.godot/imported/threat_scan_l50.png-31227c0600461fb4efb8a3bfdaf6f8b5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_scan_l50.png" +dest_files=["res://.godot/imported/threat_scan_l50.png-31227c0600461fb4efb8a3bfdaf6f8b5.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/threat_scan_safe.png.import b/artifacts/threat_scan_safe.png.import new file mode 100644 index 0000000..5695f48 --- /dev/null +++ b/artifacts/threat_scan_safe.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d13dghadaerqw" +path="res://.godot/imported/threat_scan_safe.png-418580a9bc61d12a043d8e10e7fc9664.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_scan_safe.png" +dest_files=["res://.godot/imported/threat_scan_safe.png-418580a9bc61d12a043d8e10e7fc9664.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/threat_system_overview.png.import b/artifacts/threat_system_overview.png.import new file mode 100644 index 0000000..bf43540 --- /dev/null +++ b/artifacts/threat_system_overview.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dshrybbdvwiq0" +path="res://.godot/imported/threat_system_overview.png-a766f8acff4820f25243813af732a29f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_system_overview.png" +dest_files=["res://.godot/imported/threat_system_overview.png-a766f8acff4820f25243813af732a29f.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/threat_zero_chance_event.png.import b/artifacts/threat_zero_chance_event.png.import new file mode 100644 index 0000000..f8f30fb --- /dev/null +++ b/artifacts/threat_zero_chance_event.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1i02ouvgpt0j" +path="res://.godot/imported/threat_zero_chance_event.png-81c515be7aa953c76ca944fcd24c095a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_zero_chance_event.png" +dest_files=["res://.godot/imported/threat_zero_chance_event.png-81c515be7aa953c76ca944fcd24c095a.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/threat_zero_chance_poi.png.import b/artifacts/threat_zero_chance_poi.png.import new file mode 100644 index 0000000..ac14567 --- /dev/null +++ b/artifacts/threat_zero_chance_poi.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qrcoli2qm54p" +path="res://.godot/imported/threat_zero_chance_poi.png-446d5e5246e8fe18719f712aa4fd63ef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://artifacts/threat_zero_chance_poi.png" +dest_files=["res://.godot/imported/threat_zero_chance_poi.png-446d5e5246e8fe18719f712aa4fd63ef.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/interior_deck.png b/assets/freighter/interior_deck.png new file mode 100644 index 0000000..6ee364c Binary files /dev/null and b/assets/freighter/interior_deck.png differ diff --git a/assets/freighter/interior_deck.png.import b/assets/freighter/interior_deck.png.import new file mode 100644 index 0000000..24e96a1 --- /dev/null +++ b/assets/freighter/interior_deck.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccsaqmap4b0ku" +path="res://.godot/imported/interior_deck.png-79eb644dd0f1cb0c4ed6cf1d4e5ff62d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/interior_deck.png" +dest_files=["res://.godot/imported/interior_deck.png-79eb644dd0f1cb0c4ed6cf1d4e5ff62d.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=true +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/prompts.json b/assets/freighter/prompts.json new file mode 100644 index 0000000..2cc1f1a --- /dev/null +++ b/assets/freighter/prompts.json @@ -0,0 +1,5 @@ +{ + "tool": "image_gen (built-in)", + "asset": "assets/freighter/interior_deck.png", + "prompt": "Use case: stylized-concept. Production game background: a beautifully detailed believable spacecraft INTERIOR CUTAWAY DECK, STRICT VERTICAL ORTHOGRAPHIC TOP DOWN, no roof, no perspective tilt, no visible vertical wall faces. Wide horizontal panoramic canvas approximately 1792 by 768, aspect ratio 2.33:1. Bow is LEFT, stern is RIGHT. This is the interior of a dark graphite armored military frigate with deep red trim, restrained cyan terminal lights and warm amber maintenance lights. Entire coherent continuous deck fills central 94 percent of the canvas, dark navy-black void beyond hull, NO text, NO letters, NO labels, NO diagrams or UI. Detailed realistic painted hard-surface game environment, readable believable furniture and equipment, soft overhead lighting, moderately bright floor to read well. LAYOUT MUST BE EXACT: LEFT FRONT command bridge occupies x=75..310 y=125..645, a tapered left-facing prow room with forward windows, semicircle of navigation consoles, chairs, captain station and central tactical table. A SINGLE broad straight CENTRAL CORRIDOR runs horizontally x=315..1320 y=355..425, connecting bridge at left to hangar at right; lit floor strips, clear walking route, all rooms have actual doorways opening onto this corridor. ABOVE the corridor EXACTLY FOUR LARGE ADJACENT ROOMS: room 1 WORKSHOP x=340..555 y=110..335 with equipped workbenches along walls, tool cabinets, machinery, fabrication station, loose cable spool, amber task lamps. Then EXACTLY THREE separate unfurnished expansion rooms x=575..790, x=810..1025, x=1045..1260 at y=110..335; these are UNDER RENOVATION with exposed utility conduits, unfinished floor panels, small material stacks and subtle yellow-black safety stripes at doorways, each room clearly separated by thick bulkhead walls. BELOW corridor EXACTLY FIVE SMALLER ADJACENT ROOMS x=340..505, x=525..690, x=710..875, x=895..1060, x=1080..1245 at y=445..650; all five under renovation, empty modular chambers intended for future crew cabins, folded scaffold, cable trays, dismantled panels, sealed storage crates, no active bunk beds yet. RIGHT REAR a LARGE HANGAR x=1290..1730 y=95..665: one EMPTY central landing pad centered at x=1510 y=385 with radius about 145, clean clear pad center for a separately rendered player spacecraft later, NO SPACESHIP painted into the image. Hangar perimeter has coiled cables, repair cart, tool trolley, gantry bases, fuel hoses, cargo pallets, side wall machinery and red blast doors at far right. Keep all such props outside the central landing pad. This must look like ONE REAL CONNECTED SHIP INTERIOR, with consistent metallic walls, actual doors, lighting, floors, structural ribs and believable scale, not a grid of separate illustration tiles. The workshop is finished and operational, the other 8 small/large rooms are visibly under construction. Add tiny lit consoles and practical fixtures, no humans or robots, no giant glowing symbols. Subtle floor wear and grime, lovely rich environment detail, clean readable silhouette. No title, no text anywhere, no graphic labels. Do not render the exterior ship surface on top of the rooms. Keep exact room counts and corridor arrangement." +} diff --git a/assets/freighter/room_interiors.png b/assets/freighter/room_interiors.png new file mode 100644 index 0000000..dfd9989 Binary files /dev/null and b/assets/freighter/room_interiors.png differ diff --git a/assets/freighter/room_interiors.png.import b/assets/freighter/room_interiors.png.import new file mode 100644 index 0000000..7f22a7e --- /dev/null +++ b/assets/freighter/room_interiors.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://e4qjp1a5tyd3" +path="res://.godot/imported/room_interiors.png-18f188db948f86dd4851487fda062966.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/freighter/room_interiors.png" +dest_files=["res://.godot/imported/room_interiors.png-18f188db948f86dd4851487fda062966.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=true +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/room_interiors_prompt.json b/assets/freighter/room_interiors_prompt.json new file mode 100644 index 0000000..8cc5e76 --- /dev/null +++ b/assets/freighter/room_interiors_prompt.json @@ -0,0 +1,7 @@ +{ + "tool": "image_gen (built-in)", + "mode": "reference-based generation", + "reference": "assets/freighter/interior_deck.png", + "asset": "assets/freighter/room_interiors.png", + "prompt": "Create a single game texture atlas, EXACT 2 by 2 equal square tiles filling the entire square image edge to edge, no gutters, no labels, no text. Four distinct overhead spaceship ROOM INTERIOR floor textures to overlay within existing rooms. Strict orthographic vertical TOP DOWN, no isometric, no visible outer walls, no exterior, each tile fills entire quadrant with continuous grey worn metal floor and furniture. Same high fidelity gritty realistic sci-fi painted 3D game art as reference image, charcoal metal, muted red, warm amber lamps, cyan monitors, subtle shadows. TOP LEFT: scientific laboratory with white metal experiment benches around edges, microscopes, specimen vials, central clean examination table, blue screens. TOP RIGHT: alien research department, central green glowing cylindrical containment tank with strange small alien organism seen from directly above, sealed sample cases, scanners and biohazard equipment along edges, subtle green lighting. BOTTOM LEFT: module storage room with orderly racks and crates of spaceship components along sides, three distinct modules on work pallets, overhead view mechanical hardware, amber lights and central walking space. BOTTOM RIGHT: cozy small crew cabin, bed along left wall with dark teal blanket and pillow, desk with screen top right, locker bottom right, chair and personal items, warm bedside lamp, grey floor. Each quadrant is a fully equipped separate floor tile, no borders crossing into adjacent tiles. Furniture clearly readable at small game scale. Match provided frigate interior style. Reference image is STYLE ONLY; create new atlas, do not reproduce ship." +} diff --git a/assets/planets/artwork_prompts.json b/assets/planets/artwork_prompts.json index 8fd4c9a..58282f8 100644 --- a/assets/planets/artwork_prompts.json +++ b/assets/planets/artwork_prompts.json @@ -13,7 +13,10 @@ }, "freighter": { "asset": "assets/planets/freighter.png", - "prompt": "Use case: stylized-concept. Production sprite for a premium painted top-down sci-fi 2D game. single long expedition freighter spacecraft viewed orthographically straight from above, bow facing up, broad central armored spine with six modular cargo pods, visible hangar opening with cyan light, twin engine blocks, weathered ivory and dark gunmetal with copper accents, readable silhouette. Entire object centered inside square image with 15% transparent safe margin. Sharp readable silhouette, hand-painted 3D detail, consistent soft light from upper left. Genuinely transparent exterior, no ground no stars no background no text no lettering no frame, no perspective, one object only." + "prompt": "Use case: stylized-concept. Create a replacement production spacecraft sprite for a top-down Godot game, using the attached image as the SHIP DESIGN reference, not as a camera reference. Primary request: a massive dark charcoal-black armored capital frigate like this reference, but seen from EXACTLY STRAIGHT ABOVE. Preserve the reference's visual design language: very long broad flat wedge-shaped prow, split forked pointed bow with an elongated narrow central recess, tapering long armored hull, progressively wider layered polygonal armor shoulders at the stern, stacked angular command decks, heavy industrial military slabs, restrained deep crimson-red recessed panel lines and narrow glowing red seams, dark graphite plating, a few tiny turret emplacements and geometric deck hatches. Red accents are thin and integrated, NOT a whole red ship. Powerful ominous monolithic silhouette, readable large shapes, slightly stylized high-quality hard-surface rendering with bevel highlights, no tiny noisy greeble overload. The frigate is symmetrical along its long vertical axis, bow points UP toward top of image and broad stern is at BOTTOM; engine exhaust is at bottom only. IMPORTANT camera: strict vertical orthographic TOP DOWN plan view, camera directly over the ship center, zero perspective tilt, no isometric view, NO visible vertical sides or front walls. The top of every deck is visible but sides are not. No tilted diagonal ship. Whole ship centered within a square canvas with at least 8 percent transparent safe margin on ALL edges. Slight overhead soft upper-left light, dark but clearly legible armor panels, localized subtle crimson engine light. Truly alpha-transparent exterior, no floor, no ground plane, no cast shadow on background, no stars, no grey or white backdrop. No text, logos, UI, watermarks or reference screenshot icons. One single epic military capital frigate, not a cargo-pod freighter. Output a square PNG game asset.", + "previous_prompt": "Use case: stylized-concept. Asset type: replacement production sprite for an existing top-down Godot sci-fi game, a much more epic flagship expedition frigate / mobile hangar ship. Input image is a STYLE AND FUNCTION reference: keep the weathered ivory titanium, dark gunmetal, warm bronze accents and cyan lights, upward-facing bow, strict overhead orientation, transparent background. Dramatically redesign the narrow utilitarian cargo vessel into a majestic imposing capital frigate: powerful layered armored spearhead bow at top, wide angular armored shoulders, long monumental central spine with a raised command citadel seen straight overhead, integrated ribbed cargo modules rather than exposed box pods, two distinct cyan-lit recessed hangar bays, symmetrical armored outriggers, four enormous rear engine nacelles with short restrained electric-blue exhaust. Small antenna arrays, readable panel layers and a few restrained defensive turret details. Elegant coherent silhouette, broad enough to look substantial, premium realistic painted hard-surface game art, beautiful craftsmanship, strong larger shapes that read at 190px screen size, medium detail secondary panels without noisy tiny greebles. Absolute orthographic vertical top-down view with no perspective tilt, bow pointing straight up, stern at bottom. Entire ship and engine glow within central 80 percent of a square canvas, 10 percent transparent margin on every edge, no clipping. Soft light from upper left. Single isolated ship, truly alpha-transparent exterior and negative spaces, no starfield, no space backdrop, no ground, no contact shadow, no frame, no letters, no text, no UI. Keep cyan glow localized to engines and hangars, no bloom halo over the whole silhouette. The result should feel like a proud expedition flagship, epic and formidable.", + "tool": "image_gen (built-in)", + "design_reference": "assets/planets/references/frigate_style.png" }, "lander": { "asset": "assets/planets/lander.png", @@ -39,4 +42,4 @@ "asset": "assets/planets/ruins.png", "prompt": "Use case: stylized-concept. Production PNG asset for a premium painted top-down sci-fi exploration game. one small cluster of ancient alien ruins seen orthographically directly overhead, broken pale stone concentric platforms with a mysterious turquoise core, a few toppled angular pillars, moss in cracks, realistic painted sci-fi videogame prop, isolated compact compound, no surrounding terrain. Square composition. Genuinely transparent background, entire object inside frame with 12% empty safe margin, clean alpha edges. Consistent soft overhead light from upper left. No text no letters no grid no perspective no watermark." } -} \ No newline at end of file +} diff --git a/assets/planets/cloud_mist.png b/assets/planets/cloud_mist.png new file mode 100644 index 0000000..50829ae Binary files /dev/null and b/assets/planets/cloud_mist.png differ diff --git a/assets/planets/cloud_mist.png.import b/assets/planets/cloud_mist.png.import new file mode 100644 index 0000000..06c8d0c --- /dev/null +++ b/assets/planets/cloud_mist.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ce5e1scjgjiqp" +path="res://.godot/imported/cloud_mist.png-d2646f52f72de696d85216135beba38e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/planets/cloud_mist.png" +dest_files=["res://.godot/imported/cloud_mist.png-d2646f52f72de696d85216135beba38e.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=true +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/planets/cloud_mist_prompt.json b/assets/planets/cloud_mist_prompt.json new file mode 100644 index 0000000..ec9fc22 --- /dev/null +++ b/assets/planets/cloud_mist_prompt.json @@ -0,0 +1,6 @@ +{ + "tool": "image_gen (built-in)", + "mode": "generation, transparent RGBA", + "asset": "assets/planets/cloud_mist.png", + "prompt": "Game VFX texture asset: one large wispy atmospheric cloud bank seen strictly from directly overhead, delicate realistic white and pale cool grey mist, fragmented cirrus strands mixed with soft thin stratocumulus veils, airy translucent vapor with plenty of clear gaps, varied internal density, intricate fine tendrils, soft diffused lighting, no solid rounded cartoon puffs. True transparent RGBA background, semitransparent wisps and smoothly feathered alpha fading entirely to zero well before all four image edges. Isolated irregular horizontal bank centered with generous transparent margins, no rectangle, no ground, no sky color, no shadows baked onto a backdrop, no stars, no text. Intended as a large subtle moving parallax overlay above a top-down planetary landscape and spacecraft; player must see terrain through it. Beautiful cinematic mist texture, restrained neutral color. Landscape aspect ratio." +} diff --git a/assets/planets/freighter.png b/assets/planets/freighter.png index ff2396a..d397c72 100644 Binary files a/assets/planets/freighter.png and b/assets/planets/freighter.png differ diff --git a/assets/planets/references/frigate_style.png b/assets/planets/references/frigate_style.png new file mode 100644 index 0000000..9841f34 Binary files /dev/null and b/assets/planets/references/frigate_style.png differ diff --git a/assets/planets/references/frigate_style.png.import b/assets/planets/references/frigate_style.png.import new file mode 100644 index 0000000..4bd92cf --- /dev/null +++ b/assets/planets/references/frigate_style.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5w8an0ojvvvv" +path="res://.godot/imported/frigate_style.png-3363d16ba3c46b662b911b6529cc2276.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/planets/references/frigate_style.png" +dest_files=["res://.godot/imported/frigate_style.png-3363d16ba3c46b662b911b6529cc2276.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/planet_mechanic.txt b/planet_mechanic.txt index 0bb68a2..9bc3c5e 100644 --- a/planet_mechanic.txt +++ b/planet_mechanic.txt @@ -728,3 +728,171 @@ Globalne zagrożenie i ochrona kapitana (18.10.2026): - Zweryfikowano render skanu bez zagrożenia, przy 150% i po ochronie L50, a także blokadę trzeciego etapu kopalni oraz ewakuacji. Podgląd: artifacts/threat_system_overview.png. + +Nowa grafika fregaty / frachtowca (18.10.2026): +- Zastąpiono freighter.png bardziej okazałym statkiem flagowym: szerokie + opancerzone sekcje boczne, dwa podświetlone hangary i cztery silniki. +- Zachowano widok z góry, dziób ku górze, jasny pancerz, ciemny metal, + miedziane akcenty i turkusowe światła. Grafika ma przezroczyste tło + i mipmapy. Jest używana w kosmosie oraz na ekranie frachtowca. +- Podpis w kosmosie przesunięto pod silniki, aby nie zasłaniał sylwetki. +- Źródło: wbudowany imagegen. Grafika: assets/planets/freighter.png; + pełny prompt i poprzedni prompt: assets/planets/artwork_prompts.json. +- Zweryfikowano render w obu miejscach. Podglądy: + artifacts/epic_frigate_space.png i artifacts/epic_frigate_hangar.png. + +Fregata zgodna z referencją użytkownika (18.10.2026): +- Grafika freighter.png zastąpiona ciemnym, klinowym okrętem z rozwidlonym + dziobem, szeroką warstwową rufą i czerwonymi akcentami pancerza. +- Zachowano ścisły widok pionowo z góry, dziób ku górze, przezroczystość + i mipmapy. Nowy wariant jest używany w kosmosie i ekranie frachtowca. +- Źródło: wbudowany imagegen. Referencja: assets/planets/references/frigate_style.png. + Prompt zapisany w assets/planets/artwork_prompts.json. +- Sprawdzono czytelność na tle kosmosu i wygląd w hangarze. Podglądy: + artifacts/dark_frigate_space.png i artifacts/dark_frigate_hangar.png. + +Wnętrze fregaty po zadokowaniu (18.10.2026): +- Osobna scena: scenes/planets/freighter_interior.tscn, dostępna również + do samodzielnego podglądu w edytorze Godot. +- Mostek po lewej, centralny korytarz, nad nim warsztat i trzy duże + sekcje w remoncie. Pod korytarzem pięć mniejszych pokoi w remoncie. + Hangar znajduje się po prawej, na końcu pokładu. +- Warsztat zachowuje wytwarzanie i zakładanie wyposażenia. Hangar + zachowuje naprawy lądownika i odbiór dostarczonych modułów. + Pełna ładownia nie usuwa nieodebranych modułów. Mostek pokazuje + informacje, pozostałe pokoje są rezerwą pod przyszłą rozbudowę. +- Hangar rysuje prawdziwą teksturę aktualnego statku z jego Sprite2D. + Samodzielnie uruchomiona scena używa wyboru statku z GameState. +- Wnętrze zawiera meble, konsole, przewody, narzędzia i wyposażenie + remontowe. Animowane lampy, iskry spawania i para działają przy + wstrzymanym kosmosie. ESC zamyka panel pomieszczenia, L odpina statek. +- Grafika: assets/freighter/interior_deck.png. Źródło: wbudowany imagegen; + pełny prompt: assets/freighter/prompts.json. Import z mipmapami. +- Test integracyjny tests/previews/freighter_interior_preview.tscn + przeszedł: 11 sekcji, aktualny statek, efekty podczas pauzy, warsztat, + remont, naprawy, pełna ładownia, ESC/L oraz samodzielny podgląd sceny. + Regresja planet_expeditions_test.tscn również przeszła. +- Podgląd: artifacts/freighter_interior_overview.png. + +Budowa pomieszczeń fregaty (18.10.2026): +- Kliknięcie remontowanej sekcji otwiera panel z przyciskiem ZBUDUJ + bez kosztów. Każdą sekcję można zbudować tylko raz. +- Góra od warsztatu: laboratorium, badania obcych, skład modułów. + Na dole pięć kajut załogi. Nowe pokoje mają na razie grafikę; + mechanika badań, składu i załogi zostanie dodana później. +- Każdy z ośmiu pokoi to osobna instancja freighter_room.tscn. + Warstwa remontowa i wyposażone wnętrze są wymienne, niezależnie + od kadłuba, korytarza i sąsiednich sekcji. Zachowano animowane światła. +- Stan typów pomieszczeń: eksportowane planet_progress.freighter_rooms. + Przetrwa zamknięcie sceny i ponowne dokowanie; obsługuje serializację + zasobu. Sam system zapisu całej gry nie jest częścią tej zmiany. +- Grafika: assets/freighter/room_interiors.png (atlas 2x2, mipmapy). + Wbudowany image_gen, generowanie z referencją stylu poprzedniego + pokładu. Pełny prompt: assets/freighter/room_interiors_prompt.json. +- Test freighter_interior_preview przeszedł: budowa wszystkich 8 pokoi, + brak kosztów, blokada duplikatów, serializacja zasobu, ponowne + dokowanie oraz dotychczasowy warsztat, hangar, ładownia i ESC/L. + Wizualnie sprawdzono panel budowy i cały wyposażony pokład. + Podgląd: artifacts/freighter_interior_built.png. + +Odblokowywanie slotów statku (18.10.2026): +- Nowa gra: jeden slot broni i jeden rozszerzenia. Maksymalnie 3/5. + Pięć podstawowych slotów modułów pozostaje bez zmian. +- Hangar fregaty odblokowuje kolejny slot danego typu za 10 żelaza. + Logika wymaga dokowania, sprawdza zasoby i limit przed zapłatą. +- Zablokowane sloty są oznaczone w wyposażeniu; odrzucają montaż, + nie strzelają, nie aktywują rozszerzeń i nie dają pasywnych premii. +- Liczniki odblokowań przechodzą przez preserve_for_restart razem + z wyposażeniem. Nowa rozgrywka przywraca 1/1. +- Test slot_unlock_test przeszedł: start, blokady, dokowanie, brak żelaza, + przycisk hangaru, opłaty, limity, zachowanie między układami i reset. + Regresje wnętrza fregaty i pasywnych rozszerzeń przeszły. +- Starszy tactical_extensions_test ma nieaktualne asercje cooldownów + (stałe 60 s zamiast obecnego losowania 5..30 s) i duplikatów rozszerzeń; + aktualizacja jego założeń wykracza poza zmianę slotów. +- Podgląd: artifacts/hangar_slot_unlock.png. + +Rzędy ładowni i magazyn frachtowca (18.10.2026): +- Nowy statek ma pierwszy rząd ładowni: 5 miejsc z maksymalnych 20. + Hangar odblokowuje kolejne rzędy po 5 miejsc za 10 żelaza każdy. + Wymagane dokowanie; koszt nie jest pobierany przy braku żelaza + lub osiągnięciu czterech rzędów. Stan przechodzi między układami. +- Zablokowane pola mają oznaczenie BLOKADA. Montaż, przenoszenie, + odbiór łupu i liczniki magazynu respektują aktywną pojemność. +- Przycisk MAGAZYN na frachtowcu oraz zbudowany skład modułów + otwierają magazyn. Niezbudowany skład można bezpłatnie wybudować + bezpośrednio z tej zakładki. +- Dwie kolumny: wyposażenie w ładowni i przedmioty na frachtowcu. + Przyciski ODŁÓŻ / ODBIERZ przenoszą dokładnie ten sam przedmiot + z zachowaniem parametrów. Założone wyposażenie należy wcześniej + zdjąć do ładowni. Magazyn frachtowca nie ma obecnie limitu miejsc. +- Przenoszenie wymaga dokowania i zbudowanego składu. Brak miejsca + nie usuwa przedmiotów. Ochrona przed powtórnym/starym kliknięciem + sprawdza tożsamość przedmiotu. Stan zapisany w eksportowanym + planet_progress.freighter_storage, zachowany przy zmianie układu. +- Test freighter_storage_test przeszedł: pojemność 5, blokada łupu + i przenoszenia do zamkniętych pól, opłaty i limit rzędów, budowa, + transfery w obie strony, pełna ładownia, stare przyciski, serializacja, + przejście do kolejnego układu i reset nowej gry. Przeszła również + regresja freighter_interior_preview. Zweryfikowano render magazynu. +- Podgląd: artifacts/freighter_storage.png. + +Mniej miejsc na powierzchni (18.10.2026): +- Na każdej mapie jedna kopalnia i jedne starożytne ruiny. Każdy typ + ma niezależnie 25% szans na drugi obiekt. Złoża minerałów: nadal dwa. +- Dokładnie jedno wydarzenie '?' na mapę, zamiast dawnej szansy 50%. + Gdy nie ma płaskiego terenu, generator wybiera odległe wolne miejsce + i oczyszcza otoczenie, aby wydarzenie nie znikało przez brak lokalizacji. +- Układ nadal jest deterministyczny dla ziarna mapy. +- Testy przeszły: liczby POI na 64 mapach, brak płaskiego terenu, + wydarzenia na 1000 mapach (dokładnie 1000), krajobrazy i wyprawy. + +Fregata +50% i kompaktowe karty orbitalne (18.10.2026): +- Grafika fregaty w kosmosie powiększona z 190 do 285 jednostek. + Podpis przesunięty pod większy kadłub. +- Panele kontaktu z planetą i fregatą mają 300 px szerokości, + mniejsze przyciski, nagłówek telemetryczny, delikatny cień i obramowanie. + Tło ma krycie 84%, a elementy interaktywne pozostają czytelne. +- Panel jest przy obiekcie i śledzi transformację widoku w każdej klatce. + Wybiera stronę, uwzględnia krawędzie, HUD i okno zaopatrzenia. + Dodatkowe pozycje zapobiegają nachodzeniu nagłówków dwóch kart. +- Skan pokazuje warunki, globalne zagrożenie, średnią i trzy szanse POI, + koszt lądowania oraz HP lądownika. Pełny raport ochrony w podpowiedzi. +- Zaopatrzenie przy planecie otrzymało zgodny styl, mniejsze karty ofert + i położenie przy planecie. Ręczne przesuwanie okna nadal działa. +- Testy: skala 150%, przezroczystość, zwarte wymiary, krawędzie widoku, + omijanie przeszkód, ruch widoku bez zmiany tekstu, brak nakładania kart, + zakupy, rabaty i wormhole. Regresja wypraw również przeszła. +- Podglądy: artifacts/freighter_prompt_fixed.png, + artifacts/planet_scan_stats.png, artifacts/planet_services_preview.png. + +Bliski kontakt, chmury i podstawy gór (18.10.2026): +- Panele planety i jej usług pojawiają się dopiero wewnątrz 92% promienia + tarczy planety. Kontakt z fregatą wymaga wejścia nad kadłub: elipsa + o półosiach 62/131 jednostek. Skróty skanowania, lądowania i dokowania + używają tego samego zasięgu; usługi planety również. +- Na powierzchni dodano przezroczystą mgiełkę z nowej grafiki RGBA: + assets/planets/cloud_mist.png. Wbudowany image_gen; pełny prompt + zapisany w assets/planets/cloud_mist_prompt.json. Import z mipmapami. +- Dwie warstwy wysokości przesuwają się względem widoku 1.22x i 1.34x + szybciej niż teren, dodatkowo dryfują z wiatrem. Brzegi grafiki są + wygaszone shaderem. Chmury mają z=70, statek z=30, delikatne cienie z=5. + Efekt działa w podglądzie powierzchni; HUD i minimapa pozostają czytelne. +- Góry zachowują dotychczasową grafikę. Nowy shader rozprasza krawędzie + podstaw, stopniowo wygasza ich krycie i dopasowuje podnóża do palety + podłoża biomu. Szczyty pozostają wyraźne. +- Test surface_atmosphere_test przeszedł: zasięgi, kolejność warstw, + dwie prędkości paralaksy, dryf, mipmapy i materiał przejścia gór. + Przeszły również planet_prompt_test, planet_services_preview, + planet_expeditions_test i render landscape_preview w sześciu biomach. +- Podglądy porównawcze: artifacts/surface_atmosphere_before.png, + artifacts/surface_atmosphere_mountains.png, + artifacts/surface_atmosphere_clouds.png. + +Warstwy przy fregacie i muzyka dokowania (18.10.2026): +- Fregata w kosmosie ma z=-3. Kadłub, silniki i osłona gracza są + renderowane nad nią przy nakładaniu się sylwetek. +- GameMusic ma tryb PROCESS_MODE_ALWAYS. Muzyka kontynuuje utwór + podczas pauzy dokowania oraz pobytu na powierzchni, bez restartu. +- Rozszerzony test freighter_interior_preview przeszedł: kolejność + warstw i rosnąca pozycja odtwarzania muzyki podczas zadokowania. diff --git a/resources/effects/cloud_mist.gdshader b/resources/effects/cloud_mist.gdshader new file mode 100644 index 0000000..60d5363 --- /dev/null +++ b/resources/effects/cloud_mist.gdshader @@ -0,0 +1,10 @@ +shader_type canvas_item; +render_mode unshaded; +varying vec4 tint; +void vertex() { tint=COLOR; } +void fragment() { + vec4 mist=texture(TEXTURE,UV); + vec2 border=min(UV,vec2(1.0)-UV); + float feather=smoothstep(0.025,0.15,border.x)*smoothstep(0.025,0.15,border.y); + COLOR=vec4(mist.rgb*tint.rgb,pow(mist.a,1.35)*tint.a*feather); +} diff --git a/resources/effects/cloud_mist.gdshader.uid b/resources/effects/cloud_mist.gdshader.uid new file mode 100644 index 0000000..1ab3035 --- /dev/null +++ b/resources/effects/cloud_mist.gdshader.uid @@ -0,0 +1 @@ +uid://byox58gjlxrmn diff --git a/resources/effects/mountain_blend.gdshader b/resources/effects/mountain_blend.gdshader new file mode 100644 index 0000000..cc06d9c --- /dev/null +++ b/resources/effects/mountain_blend.gdshader @@ -0,0 +1,21 @@ +shader_type canvas_item; +uniform vec4 ground_tint : source_color = vec4(0.25,0.28,0.2,1.0); +uniform vec4 rock_tint : source_color = vec4(0.4,0.4,0.36,1.0); + +float hash(vec2 p) { return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); } +float noise(vec2 p) { + vec2 i=floor(p); vec2 f=fract(p); f=f*f*(3.0-2.0*f); + return mix(mix(hash(i),hash(i+vec2(1,0)),f.x),mix(hash(i+vec2(0,1)),hash(i+vec2(1,1)),f.x),f.y); +} +void fragment() { + vec4 mountain=texture(TEXTURE,UV); + float edge=length((UV-vec2(0.5))*vec2(1.9,1.8)); + float breakup=noise(UV*25.0)*0.065+noise(UV*65.0)*0.025; + float foothill=smoothstep(0.42,0.90,edge+breakup); + float feather=1.0-smoothstep(0.62,0.96,edge+breakup); + float luminosity=dot(mountain.rgb,vec3(0.299,0.587,0.114)); + vec3 mineral=mix(mountain.rgb,rock_tint.rgb*(0.65+luminosity),0.18); + // Low foothills inherit the local biome before dissolving into the ground. + mineral=mix(mineral,ground_tint.rgb*(0.65+luminosity*0.9),foothill*0.62); + COLOR=vec4(mineral,mountain.a*feather); +} diff --git a/resources/effects/mountain_blend.gdshader.uid b/resources/effects/mountain_blend.gdshader.uid new file mode 100644 index 0000000..e3f06e7 --- /dev/null +++ b/resources/effects/mountain_blend.gdshader.uid @@ -0,0 +1 @@ +uid://cq36vsajgrgxh diff --git a/scenes/game/game.tscn b/scenes/game/game.tscn index 7bac0e1..b1fd2f8 100644 --- a/scenes/game/game.tscn +++ b/scenes/game/game.tscn @@ -25,6 +25,7 @@ size = Vector2(40, 3600) script = ExtResource("1_game") [node name="GameMusic" type="AudioStreamPlayer" parent="." unique_id=784369202] +process_mode = 3 script = ExtResource("8_scene_music") track_path = "res://assets/sounds/music/music2.mp3" playback_volume_db = -17.0 diff --git a/scenes/planets/freighter_interior.tscn b/scenes/planets/freighter_interior.tscn new file mode 100644 index 0000000..b87472c --- /dev/null +++ b/scenes/planets/freighter_interior.tscn @@ -0,0 +1,48 @@ +[gd_scene load_steps=4 format=3] +[ext_resource type="Script" path="res://scripts/planets/freighter_screen.gd" id="1"] +[ext_resource type="Script" path="res://scripts/planets/freighter_deck.gd" id="2"] +[ext_resource type="Texture2D" path="res://assets/freighter/interior_deck.png" id="3"] +[node name="FreighterInterior" type="Control"] +process_mode = 3 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1") +[node name="Background" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.014,0.024,0.035,1) +[node name="InteriorArt" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 12.0 +offset_top = 94.0 +offset_right = -12.0 +offset_bottom = -62.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +texture_filter = 4 +texture = ExtResource("3") +expand_mode = 1 +stretch_mode = 5 +[node name="Deck" type="Control" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 88.0 +offset_bottom = -56.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("2") diff --git a/scenes/planets/freighter_room.tscn b/scenes/planets/freighter_room.tscn new file mode 100644 index 0000000..0ceef6c --- /dev/null +++ b/scenes/planets/freighter_room.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://scripts/planets/freighter_room.gd" id="1"] +[node name="FreighterRoom" type="Control"] +mouse_filter = 2 +texture_filter = 4 +clip_contents = true +script = ExtResource("1") diff --git a/scripts/game/flight_hud.gd b/scripts/game/flight_hud.gd index b5ab302..8459874 100644 --- a/scripts/game/flight_hud.gd +++ b/scripts/game/flight_hud.gd @@ -418,7 +418,7 @@ func _process(_delta: float) -> void: return var inventory := player.get_node("ShipInventory") as ShipInventory _debug_item_button.text = "LOSUJ PRZEDMIOT · POZ. %d" % GameState.system_level - _debug_item_button.disabled = inventory.get_cargo_used() >= ShipInventory.CARGO_SIZE + _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 @@ -458,7 +458,7 @@ func _give_debug_ammunition() -> void: func _give_debug_item() -> bool: var inventory := player.get_node("ShipInventory") as ShipInventory _debug_item_status.show() - if inventory.get_cargo_used() >= ShipInventory.CARGO_SIZE: + if inventory.get_cargo_used() >= inventory.get_cargo_capacity(): _debug_item_status.text = "Magazyn pełny — zwolnij miejsce." _debug_item_status.add_theme_color_override("font_color", Color("ff8989")) _layout_debug.call_deferred() diff --git a/scripts/game/game.gd b/scripts/game/game.gd index 346d6e9..7ea5c13 100644 --- a/scripts/game/game.gd +++ b/scripts/game/game.gd @@ -7,7 +7,7 @@ const SERVICES_MENU := preload("res://scenes/ui/planet_services_menu.tscn") const PLANET_MARKER := preload("res://scripts/ui/protected_planet_marker.gd") const WORMHOLE_SCRIPT := preload("res://scripts/game/wormhole.gd") const WORLD_SIZE := SYSTEM_GENERATOR.WORLD_SIZE -const SERVICE_APPROACH_DISTANCE := 180.0 +const CONTACT_RANGE := preload("res://scripts/planets/orbital_contact_range.gd") const WORMHOLE_PLANET_DISTANCE := 620.0 const WORMHOLE_ENTRY_RADIUS := 48.0 const BOSS_SPAWN_DISTANCE := 1800.0 @@ -169,7 +169,7 @@ func _physics_process(_delta: float) -> void: advance_to_next_level() func is_near_protected_planet() -> bool: - return player.global_position.distance_to(protected_planet.global_position) <= float(protected_planet.get("radius")) + SERVICE_APPROACH_DISTANCE + return CONTACT_RANGE.at_planet(player,protected_planet) func open_wormhole() -> bool: if _transitioning or not system_cleared or not services_menu.visible or not is_near_protected_planet(): diff --git a/scripts/game/ship_controller.gd b/scripts/game/ship_controller.gd index 3cb7ecc..9828709 100644 --- a/scripts/game/ship_controller.gd +++ b/scripts/game/ship_controller.gd @@ -185,7 +185,7 @@ func restore_shields_from_damage(actual_damage: float) -> void: func get_passive_extension_value(effect: String) -> float: var best := 0.0 - for item in $ShipInventory.extension_slots: + for item in $ShipInventory.extension_slots.slice(0,$ShipInventory.unlocked_extension_slots): if item != null and item.is_passive_extension() and item.definition.passive_effect == effect: best = maxf(best, item.get_passive_value()) return best diff --git a/scripts/game/weapon_controller.gd b/scripts/game/weapon_controller.gd index fdf7531..be8202a 100644 --- a/scripts/game/weapon_controller.gd +++ b/scripts/game/weapon_controller.gd @@ -92,7 +92,7 @@ func _physics_process(delta: float) -> void: var is_just_pressed: bool = not mouse_over_ui and ( Input.is_action_just_pressed(action_name) or _fire_just_pressed[slot_index] ) - var item: ItemInstance = inventory.weapon_slots[slot_index] + var item: ItemInstance = inventory.get_item("weapon",slot_index) if not is_pressed or item == null or item.definition == null: _laser_lines[slot_index].visible = ( item != null diff --git a/scripts/items/loot_pickup.gd b/scripts/items/loot_pickup.gd index 6efbe6d..ab7788d 100644 --- a/scripts/items/loot_pickup.gd +++ b/scripts/items/loot_pickup.gd @@ -63,7 +63,7 @@ func _physics_process(delta: float) -> void: if distance > ATTRACTION_RADIUS: return var inventory := _player.get_node("ShipInventory") as ShipInventory - if item.definition.item_id != "energy_bank" and inventory.get_cargo_used() >= ShipInventory.CARGO_SIZE: + if item.definition.item_id != "energy_bank" and inventory.get_cargo_used() >= inventory.get_cargo_capacity(): _label.text = "%s\nMagazyn pełny" % item.definition.display_name return _label.text = item.definition.display_name diff --git a/scripts/items/ship_inventory.gd b/scripts/items/ship_inventory.gd index a79a8ab..e9c2756 100644 --- a/scripts/items/ship_inventory.gd +++ b/scripts/items/ship_inventory.gd @@ -6,12 +6,18 @@ 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 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 +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] const MODULE_NAMES := ["Tarcze", "Pancerz", "Silnik", "Reaktor", "Komputer"] const STARTING_AMMUNITION := 200 @@ -43,6 +49,9 @@ 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_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"]) weapon_slots.assign(GameState.restart_inventory["weapon"]) weapon_slots.resize(WEAPON_SLOT_COUNT) @@ -67,6 +76,9 @@ 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_weapon_slots": unlocked_weapon_slots, + "unlocked_extension_slots": unlocked_extension_slots, "cargo": cargo.duplicate(), "weapon": weapon_slots.duplicate(), "module": module_slots.duplicate(), @@ -148,6 +160,7 @@ func craft_ammunition() -> bool: return craft("ammunition") func get_item(slot_kind: String, index: int) -> ItemInstance: + if not is_slot_unlocked(slot_kind,index): return null var slots := _get_slots(slot_kind) if index < 0 or index >= slots.size(): return null @@ -178,7 +191,7 @@ func add_item(item: ItemInstance) -> bool: if item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION: item.additional_modifiers.clear() item.rarity = 0 - for index in cargo.size(): + for index in get_cargo_capacity(): if cargo[index] == null: cargo[index] = item inventory_changed.emit() @@ -186,6 +199,7 @@ func add_item(item: ItemInstance) -> bool: return false func delete_cargo_item(index: int) -> bool: + if not is_slot_unlocked("cargo",index): return false if index < 0 or index >= cargo.size() or cargo[index] == null: return false cargo[index] = null @@ -195,6 +209,7 @@ func delete_cargo_item(index: int) -> bool: return true func can_move_item(from_kind: String, from_index: int, to_kind: String, to_index: int) -> bool: + if not is_slot_unlocked(from_kind,from_index): return false var source := _get_slots(from_kind) var destination := _get_slots(to_kind) if from_index < 0 or from_index >= source.size() or to_index < 0 or to_index >= destination.size(): @@ -227,6 +242,7 @@ func can_move_item(from_kind: String, from_index: int, to_kind: String, to_index return true func _accepts_item(kind: String, index: int, item: ItemInstance) -> bool: + if not is_slot_unlocked(kind,index): return false if kind == "weapon": return item.definition.category == ItemDefinition.Category.WEAPON if kind == "module": @@ -235,12 +251,77 @@ func _accepts_item(kind: String, index: int, item: ItemInstance) -> bool: return item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION and (item.definition.active_ability != null or item.is_passive_extension()) return kind == "cargo" +func is_slot_unlocked(kind: String, index: int) -> bool: + if kind == "cargo": return index >= 0 and index < get_cargo_capacity() + if kind == "weapon": return index >= 0 and index < unlocked_weapon_slots + if kind == "extension": return index >= 0 and index < unlocked_extension_slots + 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 + +func can_use_freighter_storage(captain: Resource) -> bool: + return bool(ship.get("is_docked")) and captain.expedition.freighter_rooms.get("expansion_3","") == "module_storage" + +func store_on_freighter(index: int, expected: ItemInstance, captain: Resource) -> bool: + if not can_use_freighter_storage(captain) or not is_slot_unlocked("cargo",index): return false + var item := get_item("cargo",index) + if item == null or item != expected: return false + captain.expedition.freighter_storage.append(item) + cargo[index] = null + captain.expedition.emit_changed() + inventory_changed.emit() + return true + +func retrieve_from_freighter(index: int, expected: ItemInstance, captain: Resource) -> bool: + if not can_use_freighter_storage(captain): return false + var storage: Array = captain.expedition.freighter_storage + if index < 0 or index >= storage.size() or expected == null or storage[index] != expected: return false + var destination := -1 + for cell in get_cargo_capacity(): + if cargo[cell] == null: + destination = cell + break + if destination < 0: return false + cargo[destination] = expected + storage.remove_at(index) + captain.expedition.emit_changed() + inventory_changed.emit() + return true + +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 + +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 + captain.emit_changed() + inventory_changed.emit() + return true + func get_missile_count() -> int: return missile_ammunition func get_missile_cooldown(item: ItemInstance) -> float: var reduction := item.get_stat_total("missile_cooldown_reduction") - for equipped in weapon_slots + module_slots: + for equipped in weapon_slots.slice(0,unlocked_weapon_slots) + module_slots: if equipped != null and equipped != item: reduction += equipped.get_stat_total("missile_cooldown_reduction") return maxf(1.0, 5.0 - reduction) @@ -300,7 +381,7 @@ func _get_slots(slot_kind: String) -> Array[ItemInstance]: func _recalculate_ship_stats() -> void: var bonuses := {} - for item in weapon_slots + module_slots: + for item in weapon_slots.slice(0,unlocked_weapon_slots) + module_slots: if item == null or item.definition == null: continue for stat_key in ["kinetic_absorption", "energy_absorption", "radiation_absorption", "shield_on_damage_percent", "scanner_range", "max_hull", "max_shields", "max_energy", "max_speed", "energy_regeneration", "shield_regeneration", "hull_percent", "shield_percent", "damage_percent", "speed_percent", "experience_percent", "credits_percent", "luck_percent", "critical_chance_percent", "critical_damage_percent"]: @@ -333,7 +414,7 @@ func _restore_modules(saved: Dictionary) -> void: var index := MODULE_CATEGORIES.find(item.definition.category) if index >= 0 and module_slots[index] == null: module_slots[index] = item - elif item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION and extension_slots.has(null): + elif item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION and extension_slots.slice(0,unlocked_extension_slots).has(null): extension_slots[extension_slots.find(null)] = item else: add_item(item) @@ -351,7 +432,7 @@ func get_item_comparison(item: ItemInstance, equipped: ItemInstance) -> Array[Di func _comparison_bonuses(incoming: ItemInstance = null, outgoing: ItemInstance = null) -> Dictionary: var bonuses := {} - for item in weapon_slots + module_slots: + for item in weapon_slots.slice(0,unlocked_weapon_slots) + module_slots: if item == null or item == outgoing: continue _add_comparison_bonuses(bonuses, item) @@ -443,7 +524,7 @@ func buy_irradiated_ammunition() -> bool: func get_total_dps() -> float: var total := 0.0 var bonuses := _comparison_bonuses() - for item in weapon_slots: + 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) diff --git a/scripts/planets/expedition_controller.gd b/scripts/planets/expedition_controller.gd index 80c32cd..9c2e9bc 100644 --- a/scripts/planets/expedition_controller.gd +++ b/scripts/planets/expedition_controller.gd @@ -1,5 +1,9 @@ extends Node const UI := preload("res://scripts/planets/expedition_ui.gd") +const CONTACT := preload("res://scripts/ui/orbital_contact_style.gd") +const PROFILES := preload("res://scripts/planets/planet_profiles.gd") +const FREIGHTER_SIZE := 285.0 +const CONTACT_RANGE := preload("res://scripts/planets/orbital_contact_range.gd") var game: Node2D var player: CharacterBody2D var freighter: Node2D @@ -7,6 +11,9 @@ var screen: Control var _layer: CanvasLayer var _prompt: PanelContainer var _text: Label +var _contact_label: Label +var _prompt_target: Node2D +var _freighter_half_size := Vector2.ZERO var _scan_button: Button var _land_button: Button var _near_planet: Node2D @@ -23,31 +30,41 @@ func _ready() -> void: get_tree().auto_accept_quit = false freighter = Node2D.new() freighter.name = "Freighter" + freighter.z_index = -3 # Keep the player's hull, engines and shield above the frigate. freighter.position = Vector2(480,-270) game.add_child(freighter) var sprite := Sprite2D.new() sprite.texture = preload("res://assets/planets/freighter.png") - sprite.scale = Vector2.ONE * 190.0 / maxf(sprite.texture.get_width(),sprite.texture.get_height()) + 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,75) + 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) - _prompt = UI.panel(_layer,Vector2(440,0)) + _prompt = UI.panel(_layer,Vector2(300,0)) + _prompt.add_theme_stylebox_override("panel",CONTACT.panel_style(UI.CYAN)) var column := VBoxContainer.new() + column.add_theme_constant_override("separation",7) _prompt.add_child(column) - _text = UI.label(column,"",14) - _text.custom_minimum_size.x = 420 + _contact_label = UI.label(column,"● ŁĄCZE ORBITALNE",10,UI.CYAN) + _text = UI.label(column,"",11) + _text.add_theme_constant_override("line_spacing",3) + _text.custom_minimum_size.x = 276 _text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART var row := HBoxContainer.new() + row.add_theme_constant_override("separation",7) column.add_child(row) _scan_button = UI.button(row,"SKANUJ [F]",scan_nearby) _land_button = UI.button(row,"LĄDUJ [L]",land_nearby) + for button in [_scan_button,_land_button]: + CONTACT.compact_button(button,UI.CYAN) + button.size_flags_horizontal = Control.SIZE_EXPAND_FILL _prompt.hide() get_viewport().size_changed.connect(_layout_prompt) @@ -64,6 +81,7 @@ func _process(delta: float) -> void: if is_instance_valid(screen) or get_tree().paused or bool(player.get("_is_destroyed")): _prompt.hide() return + if _prompt.visible: _layout_prompt() _prompt_refresh_time += delta # Proximity hints do not need to rebuild at the rendering frame rate. if delta > 0 and _prompt_refresh_time < 0.1: @@ -78,10 +96,13 @@ func _refresh_prompt() -> void: if not bool(planet.get("earthlike")): continue var distance: float = player.global_position.distance_to(planet.global_position) - float(planet.get("radius")) - if distance < 190 and distance < best: + if CONTACT_RANGE.at_planet(player,planet) and distance < best: best = distance _near_planet = planet - var nearby_freighter := player.global_position.distance_squared_to(freighter.global_position) < 230.0 * 230.0 + var nearby_freighter := CONTACT_RANGE.at_freighter(player,freighter) + if nearby_freighter: _prompt_target = freighter + elif is_instance_valid(_near_planet): _prompt_target = _near_planet + else: _prompt_target = player var has_destination := nearby_freighter or is_instance_valid(_near_planet) if not has_destination and _message_time <= 0: _prompt.hide() @@ -96,14 +117,21 @@ func _refresh_prompt() -> void: var text := "" if _message_time > 0: text = _message + _contact_label.text = "● RAPORT WYPRAWY" + _prompt.tooltip_text = "" elif nearby_freighter: - text = "FRACHTOWIEC · Hangar / Warsztat / Laboratorium" + _contact_label.text = "● FREGATA / POŁĄCZENIE GOTOWE" + text = "FRACHTOWIEC\nHangar · Warsztat · Magazyn" + _prompt.tooltip_text = "Zadokuj, aby naprawić lądownik, rozbudować statek i przenieść wyposażenie." else: var profile: Dictionary = _near_planet.planet_profile + _contact_label.text = "● TELEMETRIA / "+("SKAN GOTOWY" if GameState.captain.expedition.scans.has(profile.id) else "NIEZBADANA PLANETA") if GameState.captain.expedition.scans.has(profile.id): - text = preload("res://scripts/planets/planet_profiles.gd").scan_description(profile,GameState.captain) + text = _compact_scan(profile) + _prompt.tooltip_text = PROFILES.scan_description(profile,GameState.captain) else: text = "%s / EARTHLIKE\nZeskanuj warunki przed lądowaniem." % profile.name + _prompt.tooltip_text = "Skan ujawni warunki, zagrożenie i szanse powodzenia POI." if blocked and _message_time <= 0: text += "\nDokowanie i lądowanie zablokowane podczas walki." var changed := _text.text != text or _scan_button.visible != (is_instance_valid(_near_planet) and not nearby_freighter) or _land_button.visible != has_destination @@ -121,9 +149,21 @@ func _refresh_prompt() -> void: func _layout_prompt() -> void: if not is_instance_valid(_prompt): return - _prompt.size = Vector2(460, _prompt.get_combined_minimum_size().y) + _prompt.size = Vector2(300, _prompt.get_combined_minimum_size().y) var viewport_size := get_viewport().get_visible_rect().size - _prompt.position = Vector2((viewport_size.x - _prompt.size.x) * 0.5, maxf(16, viewport_size.y - _prompt.size.y - 160)) + var target: Node2D = _prompt_target if is_instance_valid(_prompt_target) else player + var canvas := target.get_global_transform_with_canvas() + var radius := _freighter_half_size.x if target == freighter else float(target.get("radius")) if target != player else 30.0 + var vertical := _freighter_half_size.y if target == freighter else radius + var obstacles: Array[Rect2] = CONTACT.hud_obstacles(game.get_node_or_null("HUD/HUDRoot")) + var services: Control = game.get("services_menu") + if is_instance_valid(services) and services.is_visible_in_tree(): obstacles.append(services.get_global_rect().grow(8)) + _prompt.position = CONTACT.beside(canvas.origin,radius*canvas.x.length(),_prompt.size,viewport_size,obstacles,true,vertical*canvas.y.length()) + +func _compact_scan(profile: Dictionary) -> String: + var captain: Resource = GameState.captain + var report: Dictionary = PROFILES.threat_report(profile,captain) + return "%s · %s\nTLEN %d%% · TEMP %d°C · BIO %d/50\nZAGROŻENIE: %.1f%% / 300%%\nŚREDNIA SZANSA POI: %.1f%%\nEtapy: %.1f%% / %.1f%% / %.1f%%\nLądowanie −%d HP · Lądownik %d%%" % [profile.name,PROFILES.biome_name(profile),profile.oxygen,profile.temperature,profile.flora,report.total,PROFILES.average_success_chance(profile,captain)*100,PROFILES.success_chance(profile,captain,0)*100,PROFILES.success_chance(profile,captain,1)*100,PROFILES.success_chance(profile,captain,2)*100,profile.landing_damage,ceili(captain.expedition.lander_hp)] func _unhandled_key_input(event: InputEvent) -> void: @@ -152,7 +192,7 @@ func land_nearby() -> void: if combat_blocked(): _notice("Odsuń się od przeciwników i zakończ walkę.") return - if player.global_position.distance_to(freighter.global_position) < 230: + if CONTACT_RANGE.at_freighter(player,freighter): open_freighter() return if not is_instance_valid(_near_planet): @@ -174,9 +214,10 @@ func land_nearby() -> void: _layer.add_child(screen) func open_freighter() -> void: + if is_instance_valid(screen): + return _enter() - screen = Control.new() - screen.set_script(preload("res://scripts/planets/freighter_screen.gd")) + screen = preload("res://scenes/planets/freighter_interior.tscn").instantiate() screen.captain = GameState.captain screen.inventory = player.get_node("ShipInventory") screen.closed.connect(_leave) diff --git a/scripts/planets/freighter_deck.gd b/scripts/planets/freighter_deck.gd new file mode 100644 index 0000000..cf30082 --- /dev/null +++ b/scripts/planets/freighter_deck.gd @@ -0,0 +1,219 @@ +extends Control +signal section_selected(section: String) +signal section_hovered(section: String) +const DESIGN_SIZE := Vector2(1792,768) +const ROOMS := [ + {"id":"command","title":"CENTRUM DOWODZENIA","status":"MOSTEK","rect":Rect2(25,165,315,435),"tag":Vector2(88,68),"active":false}, + {"id":"workshop","title":"WARSZTAT","status":"OPERACYJNY","rect":Rect2(360,120,255,205),"tag":Vector2(360,58),"active":true}, + {"id":"expansion_1","title":"SEKCJA 02","status":"W REMONCIE","rect":Rect2(632,120,200,205),"tag":Vector2(632,58),"active":false}, + {"id":"expansion_2","title":"SEKCJA 03","status":"W REMONCIE","rect":Rect2(848,120,214,205),"tag":Vector2(848,58),"active":false}, + {"id":"expansion_3","title":"SEKCJA 04","status":"W REMONCIE","rect":Rect2(1073,120,200,205),"tag":Vector2(1073,58),"active":false}, + {"id":"cabin_1","title":"POKÓJ 01","status":"W REMONCIE","rect":Rect2(363,439,151,184),"tag":Vector2(363,667),"active":false}, + {"id":"cabin_2","title":"POKÓJ 02","status":"W REMONCIE","rect":Rect2(528,439,155,184),"tag":Vector2(528,667),"active":false}, + {"id":"cabin_3","title":"POKÓJ 03","status":"W REMONCIE","rect":Rect2(696,439,184,184),"tag":Vector2(696,667),"active":false}, + {"id":"cabin_4","title":"POKÓJ 04","status":"W REMONCIE","rect":Rect2(894,439,159,184),"tag":Vector2(894,667),"active":false}, + {"id":"cabin_5","title":"POKÓJ 05","status":"W REMONCIE","rect":Rect2(1068,439,204,184),"tag":Vector2(1068,667),"active":false}, + {"id":"hangar","title":"HANGAR","status":"STATEK ZABEZPIECZONY","rect":Rect2(1305,115,435,530),"tag":Vector2(1335,42),"active":true} +] +var ship_texture: Texture2D +const ROOM_SCENE := preload("res://scenes/planets/freighter_room.tscn") +const ROOM_PLANS := { + "expansion_1":{"kind":"laboratory","title":"LABORATORIUM","description":"Stanowiska analityczne, aparatura i stół do doświadczeń."}, + "expansion_2":{"kind":"alien_research","title":"BADANIA OBCYCH","description":"Izolowane próbki i komora do badań obcych organizmów."}, + "expansion_3":{"kind":"module_storage","title":"SKŁAD MODUŁÓW","description":"Regały, pojemniki i stanowiska do przechowywania modułów."} +} +var room_states: Dictionary = {} +var room_nodes: Dictionary = {} +var ship_name := "STATEK GRACZA" +var selected := "" +var hovered := "" +var _tag_styles: Dictionary = {} +var _art: Texture2D +var _time := 0.0 +var _frame_time := 0.0 +var _art_rect := Rect2() + +func _ready() -> void: + texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS + mouse_filter = Control.MOUSE_FILTER_STOP + clip_contents = true + _art = load("res://assets/freighter/interior_deck.png") + resized.connect(func(): _layout_rooms(); queue_redraw()) + mouse_exited.connect(func(): _set_hover("")) + +func room(id: String) -> Dictionary: + for section in ROOMS: + if section.id == id: + var data: Dictionary = section.duplicate() + if is_buildable(id): + data.title = plan(id).title + data.status = "ZBUDOWANO" if is_built(id) else "W REMONCIE" + data.active = is_built(id) + return data + return {} + +func is_buildable(id: String) -> bool: + return ROOM_PLANS.has(id) or id in ["cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"] + +func plan(id: String) -> Dictionary: + if ROOM_PLANS.has(id): return ROOM_PLANS[id] + if id.begins_with("cabin_"): + return {"kind":"crew_cabin","title":"KAJUTA %02d" % int(id.trim_prefix("cabin_")),"description":"Pokój załogi z łóżkiem, biurkiem i miejscem na rzeczy osobiste."} + return {} + +func is_built(id: String) -> bool: + return room_states.get(id,"") == str(plan(id).get("kind","invalid")) + +func sync_rooms(states: Dictionary) -> void: + room_states = states + for section in ROOMS: + var id: String = section.id + if not is_buildable(id): continue + if not room_nodes.has(id): + var node := ROOM_SCENE.instantiate() + node.name = id + node.show_behind_parent = true + add_child(node) + room_nodes[id] = node + room_nodes[id].configure(id,plan(id).kind,section.rect,is_built(id)) + _layout_rooms() + _tag_styles.clear() + queue_redraw() + +func _layout_rooms() -> void: + var bounds := art_rect() + for id in room_nodes: + var area: Rect2 = room(id).rect + room_nodes[id].position = bounds.position + area.position / DESIGN_SIZE * bounds.size + room_nodes[id].size = area.size / DESIGN_SIZE * bounds.size + +func art_rect() -> Rect2: + if _art == null: + return Rect2() + var factor := minf((size.x-24)/_art.get_width(),(size.y-12)/_art.get_height()) + var extent := _art.get_size()*maxf(0.01,factor) + return Rect2((size-extent)*0.5,extent) + +func design_to_local(point: Vector2) -> Vector2: + var bounds := art_rect() + return bounds.position+point/DESIGN_SIZE*bounds.size + +func section_at(point: Vector2) -> String: + var bounds := art_rect() + if not bounds.has_point(point): + return "" + var at := (point-bounds.position)/bounds.size*DESIGN_SIZE + for section in ROOMS: + if (section.rect as Rect2).has_point(at): + return str(section.id) + return "" + +func _set_hover(id: String) -> void: + if hovered == id: + return + hovered = id + mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if not id.is_empty() else Control.CURSOR_ARROW + var data := room(id) + tooltip_text = "%s · %s" % [data.title,data.status] if not data.is_empty() else "" + section_hovered.emit(id) + queue_redraw() + +func _gui_input(event: InputEvent) -> void: + if event is InputEventMouseMotion: + _set_hover(section_at(event.position)) + elif event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + var id := section_at(event.position) + if not id.is_empty(): + selected = id + section_selected.emit(id) + accept_event() + queue_redraw() + +func _process(delta: float) -> void: + _time += delta + _frame_time += delta + if _frame_time >= 1.0/30.0: + _frame_time = 0 + queue_redraw() + +func _glow(at: Vector2, radius: float, color: Color, strength: float) -> void: + for layer in 4: + draw_circle(at,radius*(1.0-float(layer)*0.2),Color(color,strength*(0.025+layer*0.018))) + draw_circle(at,maxf(1.2,radius*0.12),Color(color,minf(1,strength*0.85))) + +func _draw() -> void: + if _art == null: + return + _art_rect = art_rect() + # The native InteriorArt node stores the background in the editable scene. + draw_set_transform(_art_rect.position,0,_art_rect.size/DESIGN_SIZE) + for section_data in ROOMS: + var section: Dictionary = room(section_data.id) + var tint := Color("78d9d8") if section.active else Color("d1a15d") + if section.id == "command": + tint = Color("91b5c0") + if section.id == hovered or section.id == selected: + draw_rect(section.rect,Color(tint,0.045 if section.id == selected else 0.025)) + draw_rect(section.rect,Color(tint,0.65),false,2.0,true) + _draw_ship() + # Powered floor strips follow the central corridor instead of flashing the whole room. + for index in 8: + var x := 355.0+float(index)*117.0 + var pulse := 0.3+0.7*maxf(0,sin(_time*1.8-index*0.6)) + draw_line(Vector2(x,393),Vector2(x+32,393),Color(0.32,0.85,0.88,0.12+pulse*0.30),2.0,true) + _glow(Vector2(x+16,393),10,Color("5ed8de"),pulse*0.65) + for index in 9: + var at := Vector2(368+index*99,340 if index < 4 else 438) + _glow(at,9,Color("efad55"),0.25+0.65*maxf(0,sin(_time*2.2+index))) + for at in [Vector2(1430,245),Vector2(1620,245),Vector2(1430,552),Vector2(1620,552)]: + _glow(at,20,Color("64dadd"),0.7+0.2*sin(_time*1.4)) + _glow(Vector2(1680,390),23,Color("ed7659"),0.2+0.65*maxf(0,sin(_time*3.0))) + for index in 5: + _glow([Vector2(110,260),Vector2(95,330),Vector2(105,410),Vector2(140,480),Vector2(290,210)][index],8,Color("6be0e1"),0.3+0.6*maxf(0,sin(_time*2.7+index*2.0))) + # Occasional tiny welding sparks beside the workshop workbench. + var weld := fmod(_time,4.8) + if weld > 3.9 and weld < 4.3: + var origin := Vector2(512,185) + _glow(origin,24,Color("b5e9f6"),0.6+0.3*sin(_time*59)) + for index in 7: + var ray := Vector2.from_angle(index*1.1+_time*5)*float(8+index*2) + draw_line(origin+ray*0.3,origin+ray,Color(0.95,0.73,0.35,0.7),1.2,true) + # Fine vapour drifting from a hangar service vent. + for index in 4: + var phase := fmod(_time*0.18+index*0.25,1.0) + var at := Vector2(1665+sin(phase*5+index)*9,569-phase*56) + draw_arc(at,6+phase*13,0.5,3.8,14,Color(0.62,0.75,0.76,(1-phase)*0.11),2.0,true) + for section in ROOMS: + _draw_tag(room(section.id)) + draw_set_transform(Vector2.ZERO) + +func _draw_ship() -> void: + if ship_texture == null: + return + var extent := ship_texture.get_size()*235.0/maxf(ship_texture.get_width(),ship_texture.get_height()) + var ship_at := Vector2(1510,394) + var scale_value := _art_rect.size/DESIGN_SIZE + draw_set_transform(_art_rect.position+(ship_at+Vector2(7,8))*scale_value,-PI*0.5,scale_value) + draw_texture_rect(ship_texture,Rect2(-extent*0.5,extent),false,Color(0,0,0,0.45)) + draw_set_transform(_art_rect.position+ship_at*scale_value,-PI*0.5,scale_value) + draw_texture_rect(ship_texture,Rect2(-extent*0.5,extent),false) + draw_set_transform(_art_rect.position,0,scale_value) + +func _draw_tag(section: Dictionary) -> void: + var font := get_theme_default_font() + var point: Vector2 = section.tag + var width := 270.0 if section.id == "hangar" else (260.0 if section.id == "command" else (160.0 if str(section.id).begins_with("cabin") else (240.0 if section.id == "workshop" else 200.0))) + var color := Color("79d9d8") if section.active else Color("c9a06c") + if section.id == "command": color = Color("a1bcc4") + 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.border_color = Color(color,0.38) + box.set_border_width_all(1) + box.set_corner_radius_all(4) + _tag_styles[section.id] = box + draw_style_box(box,Rect2(point,Vector2(width,43))) + draw_circle(point+Vector2(10,13),2.8,Color(color,0.65+0.25*sin(_time*1.8))) + draw_string(font,point+Vector2(20,19),section.title,HORIZONTAL_ALIGNMENT_LEFT,width-25,13 if section.id == "expansion_2" else 16,color) + draw_string(font,point+Vector2(10,35),section.status,HORIZONTAL_ALIGNMENT_LEFT,width-15,13,Color("899a9b")) diff --git a/scripts/planets/freighter_deck.gd.uid b/scripts/planets/freighter_deck.gd.uid new file mode 100644 index 0000000..1b8fac1 --- /dev/null +++ b/scripts/planets/freighter_deck.gd.uid @@ -0,0 +1 @@ +uid://cgriqm2tupn64 diff --git a/scripts/planets/freighter_room.gd b/scripts/planets/freighter_room.gd new file mode 100644 index 0000000..601b288 --- /dev/null +++ b/scripts/planets/freighter_room.gd @@ -0,0 +1,40 @@ +extends Control +## A replaceable room layer. Hull and corridor belong to the parent deck. +var room_id := "" +var room_kind := "" +var built := false +var design_rect := Rect2() +var _renovation: AtlasTexture +var _furnished: AtlasTexture +var _time := 0.0 + +func configure(id: String, kind: String, bounds: Rect2, complete: bool) -> void: + room_id = id + room_kind = kind + design_rect = bounds + built = complete + _renovation = AtlasTexture.new() + _renovation.atlas = preload("res://assets/freighter/interior_deck.png") + var original_size := _renovation.atlas.get_size() + _renovation.region = Rect2(bounds.position / Vector2(1792,768) * original_size, bounds.size / Vector2(1792,768) * original_size) + _furnished = AtlasTexture.new() + _furnished.atlas = preload("res://assets/freighter/room_interiors.png") + var tile := _furnished.atlas.get_size() / 2.0 + var index: int = {"laboratory":0,"alien_research":1,"module_storage":2,"crew_cabin":3}.get(kind,3) + _furnished.region = Rect2(Vector2(index % 2,floori(index / 2.0)) * tile,tile) + queue_redraw() + +func _process(delta: float) -> void: + _time += delta + if built: queue_redraw() + +func _draw() -> void: + if _renovation == null: return + draw_texture_rect(_renovation,Rect2(Vector2.ZERO,size),false) + if not built: return + # Leave structural walls and door threshold from the shared deck intact. + var inset := size * Vector2(0.045,0.045) + draw_texture_rect(_furnished,Rect2(inset,size-inset*2),false) + var light := Color("71dbe1") if room_kind != "alien_research" else Color("8ddd82") + light.a = 0.35 + 0.25 * sin(_time * 2.0 + design_rect.position.x) + draw_circle(size * Vector2(0.78,0.12),2.0,light) diff --git a/scripts/planets/freighter_room.gd.uid b/scripts/planets/freighter_room.gd.uid new file mode 100644 index 0000000..a5d8d28 --- /dev/null +++ b/scripts/planets/freighter_room.gd.uid @@ -0,0 +1 @@ +uid://dqe3uahl3adxa diff --git a/scripts/planets/freighter_screen.gd b/scripts/planets/freighter_screen.gd index a89ab45..908b350 100644 --- a/scripts/planets/freighter_screen.gd +++ b/scripts/planets/freighter_screen.gd @@ -2,133 +2,355 @@ extends Control signal closed const UI := preload("res://scripts/planets/expedition_ui.gd") const GEAR := preload("res://scripts/planets/captain_equipment.gd") +const CATALOG := preload("res://scripts/game/ship_catalog.gd") var captain: Resource var inventory: Node var _content: VBoxContainer -var _tab := "hangar" +var _tab := "overview" +var _drawer: PanelContainer +var _drawer_title: Label +var _wallet: Label +var _hint: Label +var _owned_open := false +@onready var deck: Control = $Deck func _ready() -> void: - set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) - var background := ColorRect.new() - background.color = Color("#050e18") - background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) - add_child(background) - var margin := MarginContainer.new() - margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) - for side in ["left","right","top","bottom"]: - margin.add_theme_constant_override("margin_"+side, 30) - add_child(margin) - var rows := VBoxContainer.new() - rows.add_theme_constant_override("separation", 18) - margin.add_child(rows) - var header := HBoxContainer.new() - rows.add_child(header) - var title := UI.label(header, "FRACHTOWIEC / POKŁAD OPERACYJNY", 27, UI.CYAN) - title.size_flags_horizontal = Control.SIZE_EXPAND_FILL - UI.button(header, "ODLOT [L / ESC]", func(): closed.emit()) - var main := HBoxContainer.new() - main.add_theme_constant_override("separation", 25) - main.size_flags_vertical = Control.SIZE_EXPAND_FILL - rows.add_child(main) - var schematic := UI.panel(main, Vector2(300, 0)) - schematic.size_flags_horizontal = Control.SIZE_EXPAND_FILL - schematic.size_flags_stretch_ratio = 0.8 - var left := VBoxContainer.new() - left.add_theme_constant_override("separation", 14) - schematic.add_child(left) - UI.label(left, "TWÓJ MOBILNY PORT", 18, UI.CYAN) - var art := TextureRect.new() - art.texture = preload("res://assets/planets/freighter.png") - art.expand_mode = TextureRect.EXPAND_IGNORE_SIZE - art.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED - art.size_flags_vertical = Control.SIZE_EXPAND_FILL - art.custom_minimum_size = Vector2(260, 200) - left.add_child(art) - for entry in [["hangar","01 HANGAR"],["workshop","02 WARSZTAT"],["lab","03 LABORATORIUM"]]: - var key: String = entry[0] - UI.button(left, entry[1], func(): _tab = key; _refresh()) - UI.label(left, "Frachtowiec podąża do kolejnego układu.\nZasoby i wyposażenie należą do kapitana.", 13) - var right := UI.panel(main, Vector2(530, 0)) - right.size_flags_horizontal = Control.SIZE_EXPAND_FILL - var scroll := ScrollContainer.new() - scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED - right.add_child(scroll) - _content = VBoxContainer.new() - _content.size_flags_horizontal = Control.SIZE_EXPAND_FILL - _content.add_theme_constant_override("separation", 14) - scroll.add_child(_content) - UI.label(rows, "Kosmos czeka na Twój powrót. • Naprawa lądownika: 1 część za 1% HP.", 14) + if captain == null: + captain = GameState.captain + deck.sync_rooms(captain.expedition.freighter_rooms) + deck.section_selected.connect(_select_section) + deck.section_hovered.connect(_hover_section) + var chassis := CATALOG.for_path(GameState.selected_ship_path) + deck.ship_name = str(chassis.name) + var sprite: Sprite2D + if is_instance_valid(inventory): + var ship: Node = inventory.get_parent() + sprite = ship.get_node_or_null("Sprite2D") as Sprite2D + deck.ship_texture = sprite.texture if sprite != null else load(CATALOG.texture_path(chassis)) + if sprite != null: + deck.ship_name = str(CATALOG.for_path(sprite.texture.resource_path).name) + _build_header() + _build_footer() + _build_drawer() + resized.connect(_layout) + captain.changed.connect(_sync_header) + _sync_header() + _layout() _refresh() +func _build_header() -> void: + var header := HBoxContainer.new() + header.name = "Header" + header.set_anchors_and_offsets_preset(Control.PRESET_TOP_WIDE) + header.offset_left = 26 + header.offset_right = -26 + header.offset_top = 20 + header.add_theme_constant_override("separation",22) + add_child(header) + var heading := VBoxContainer.new() + heading.size_flags_horizontal = Control.SIZE_EXPAND_FILL + header.add_child(heading) + UI.label(heading,"FREGATA / POKŁAD OPERACYJNY",24,Color("e3e9e8")) + UI.label(heading,"01 / POKŁAD GŁÓWNY · POŁĄCZENIE ZABEZPIECZONE",11,Color("77969f")) + _wallet = UI.label(header,"",13,Color("c9aa7c")) + _wallet.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + UI.button(header,"MAGAZYN",func(): _select_section("storage")) + UI.button(header,"ODLOT [L]",func(): closed.emit()) + +func _build_footer() -> void: + var footer := HBoxContainer.new() + footer.name = "Footer" + footer.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_WIDE) + footer.offset_left = 26 + footer.offset_right = -26 + footer.offset_top = -43 + footer.offset_bottom = -12 + add_child(footer) + _hint = UI.label(footer,"Wybierz pomieszczenie na pokładzie. · Warsztat i hangar są dostępne.",12,Color("91a9ae")) + _hint.size_flags_horizontal = Control.SIZE_EXPAND_FILL + footer.add_theme_constant_override("separation",18) + UI.label(footer,"● OPERACYJNE",11,Color("79d9d8")) + UI.label(footer,"● W REMONCIE",11,Color("bca078")) + +func _build_drawer() -> void: + _drawer = UI.panel(self) + _drawer.name = "SectionPanel" + var stack := VBoxContainer.new() + stack.add_theme_constant_override("separation",14) + _drawer.add_child(stack) + var row := HBoxContainer.new() + stack.add_child(row) + _drawer_title = UI.label(row,"",20,UI.CYAN) + _drawer_title.size_flags_horizontal = Control.SIZE_EXPAND_FILL + UI.button(row,"×",_close_section) + var scroll := ScrollContainer.new() + scroll.name = "SectionScroll" + scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + stack.add_child(scroll) + _content = VBoxContainer.new() + _content.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _content.add_theme_constant_override("separation",14) + scroll.add_child(_content) + +func _layout() -> void: + if not is_instance_valid(_drawer): return + var viewport_size := size + var width := minf(760 if _tab == "storage" or (_tab == "expansion_3" and deck.is_built(_tab)) else 460,viewport_size.x-40) + _drawer.position = Vector2(20 if _tab == "hangar" else viewport_size.x-width-20,94) + _drawer.size = Vector2(width,maxf(240,viewport_size.y-154)) + +func _sync_header() -> void: + if is_instance_valid(_wallet): + _wallet.text = "%d KREDYTÓW\n%d CZĘŚCI" % [captain.credits,floori(captain.parts)] + +func _hover_section(section: String) -> void: + var data: Dictionary = deck.room(section) + _hint.text = "%s / %s" % [data.title,data.status] if not data.is_empty() else "Wybierz pomieszczenie na pokładzie. · Warsztat i hangar są dostępne." + +func _select_section(section: String) -> void: + _tab = section + deck.selected = section + _refresh() + +func _close_section() -> void: + _tab = "overview" + deck.selected = "" + _drawer.hide() + deck.queue_redraw() + func _input(event: InputEvent) -> void: - if event is InputEventKey and event.pressed and not event.echo and event.keycode in [KEY_L, KEY_ESCAPE]: + if not event is InputEventKey or not event.pressed or event.echo: + return + if event.keycode not in [KEY_L,KEY_ESCAPE]: + return + # Docking removes this scene immediately, so consume input before emitting closed. + get_viewport().set_input_as_handled() + if event.keycode == KEY_L: closed.emit() - get_viewport().set_input_as_handled() + elif _drawer.visible: + _close_section() + else: + closed.emit() + +func _label(text: String, size_value := 14, color := Color("c5d3d7")) -> Label: + var node := UI.label(_content,text,size_value,color) + node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + return node func _refresh() -> void: for child in _content.get_children(): _content.remove_child(child) child.queue_free() + _sync_header() + if _tab == "overview": + _drawer.hide() + return + _drawer.show() + _layout() + _content.get_parent().set("scroll_vertical",0) + if _tab == "workshop": + _drawer_title.text = "WARSZTAT" + _build_workshop() + elif _tab == "hangar": + _drawer_title.text = "HANGAR / OBSŁUGA" + _build_hangar() + elif _tab == "command": + _drawer_title.text = "CENTRUM DOWODZENIA" + _build_command() + elif _tab == "storage" or (_tab == "expansion_3" and deck.is_built(_tab)): + _drawer_title.text = "MAGAZYN FRACHTOWCA" + _build_storage() + else: + _build_room() + +func _build_room() -> void: + var section: Dictionary = deck.room(_tab) + _drawer_title.text = str(section.get("title","SEKCJA ROZWOJOWA")) + if not deck.is_buildable(_tab): + _label("Wybierz pomieszczenie na pokładzie.") + return + var plan: Dictionary = deck.plan(_tab) + _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 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")) + UI.button(_content,"ZBUDUJ · BEZ KOSZTÓW",_construct_room.bind(_tab)) + UI.button(_content,"Wróć na pokład",_close_section) + +func _construct_room(id: String) -> void: + if not deck.is_buildable(id) or deck.is_built(id): return + captain.expedition.freighter_rooms[id] = str(deck.plan(id).kind) + captain.expedition.emit_changed() + deck.sync_rooms(captain.expedition.freighter_rooms) + _hover_section(id) + _refresh() + +func _build_hangar() -> void: var progress: Resource = captain.expedition - if _tab == "hangar": - UI.label(_content, "HANGAR / LĄDOWNIK", 24, UI.CYAN) - UI.label(_content, "Kadłub lądownika: %d / 100 HP" % ceili(progress.lander_hp), 19) - var bar := ProgressBar.new() - bar.value = progress.lander_hp - bar.custom_minimum_size.y = 25 - _content.add_child(bar) - var cost: int = progress.repair_cost() - UI.label(_content, "Części: %d · Koszt naprawy: %d" % [captain.parts, cost], 16) - var repair := UI.button(_content, "NAPRAW DO 100%% · %d części" % cost, func(): - progress.repair(captain) + _build_slot_upgrades() + _label("ZADOKOWANO / "+deck.ship_name.to_upper(),15,Color("8bd9d0")) + _label("Twój statek stoi na stanowisku serwisowym. Obsługa lądownika i odbiór odzyskanych modułów są dostępne poniżej.") + _label("Lądownik: %d / 100 HP" % ceili(progress.lander_hp),18) + var bar := ProgressBar.new() + bar.value = progress.lander_hp + bar.custom_minimum_size.y = 17 + _content.add_child(bar) + var cost: int = progress.repair_cost() + _label("Części: %d · potrzebne do naprawy: %d" % [captain.parts,cost],13) + var repair := UI.button(_content,"NAPRAW DO 100%% · %d części" % cost,func(): + progress.repair(captain) + _refresh()) + repair.disabled = cost == 0 or captain.parts < cost + _label("1 część przywraca 1 punkt procentowy HP lądownika. Do następnego lądowania wymagany jest pełny kadłub.",13,Color("819ca5")) + _label("MODUŁY DO ODEBRANIA: %d" % progress.delivered_modules.size(),16,UI.CYAN) + var delivery := UI.button(_content,"ODBIERZ DO ŁADOWNI STATKU",func(): + if is_instance_valid(inventory): progress.deliver_modules(inventory) + _refresh()) + delivery.disabled = progress.delivered_modules.is_empty() or not is_instance_valid(inventory) + _label("Moduły bez miejsca w ładowni pozostają bezpiecznie na pokładzie.",13,Color("819ca5")) + +func _build_slot_upgrades() -> void: + _label("ROZBUDOWA SLOTÓW STATKU",17,UI.CYAN) + if not is_instance_valid(inventory): + _label("Zadokuj swoim statkiem, aby rozbudować sloty.") + return + _label("Żelazo: %d · koszt kolejnego slotu: 10" % int(captain.minerals.get("iron",0)),14) + _label("Ładownia: %d / %d miejsc · rzędy %d / %d" % [inventory.get_cargo_capacity(),inventory.CARGO_SIZE,inventory.unlocked_cargo_rows,inventory.CARGO_ROW_COUNT],14) + if inventory.unlocked_cargo_rows < inventory.CARGO_ROW_COUNT: + var cargo_unlock := UI.button(_content,"ODBLOKUJ RZĄD ŁADOWNI · 10 żelaza",func(): + inventory.unlock_cargo_row(captain) _refresh()) - repair.disabled = cost == 0 or captain.parts < cost - UI.label(_content, "Lądowanie wymaga 100% sprawności.\nWejście w atmosferę zużywa 5–20 HP.\nZniszczenie lądownika zabiera tylko łup bieżącej wyprawy.", 15) - UI.label(_content, "MODUŁY DO ODEBRANIA: %d" % progress.delivered_modules.size(), 18, UI.CYAN) - var delivery := UI.button(_content, "Przenieś moduły do ładowni statku", func(): - progress.deliver_modules(inventory) - _refresh()) - delivery.disabled = progress.delivered_modules.is_empty() - UI.label(_content, "Jeśli ładownia jest pełna, moduły czekają na odbiór.", 13) - elif _tab == "workshop": - UI.label(_content, "WARSZTAT / EKWIPUNEK KAPITANA", 23, UI.CYAN) - UI.label(_content, "Każdy poziom usuwa 2 pp odpowiedniego zagrożenia.\nL50 neutralizuje je całkowicie. Sprzęt powstaje w warsztacie.", 15) - for kind in GEAR.KINDS: - var card := UI.panel(_content) - var row := HBoxContainer.new() - row.add_theme_constant_override("separation", 14) - card.add_child(row) - var icon := TextureRect.new() - icon.texture = GEAR.icon(kind) - icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE - icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED - icon.custom_minimum_size = Vector2(70,70) - row.add_child(icon) - var column := VBoxContainer.new() - column.size_flags_horizontal = Control.SIZE_EXPAND_FILL - row.add_child(column) - UI.label(column, "%s · POZ. %d" % [GEAR.NAMES[kind], GEAR.next_level(captain,kind)], 18) - var recipe := UI.label(column, GEAR.recipe_text(captain,kind), 13) - recipe.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - var button := UI.button(column, "WYTWÓRZ I ZAŁÓŻ", _craft.bind(kind)) - button.disabled = not GEAR.can_craft(captain,kind) - UI.label(_content, "POSIADANE WYPOSAŻENIE", 18, UI.CYAN) + cargo_unlock.disabled = not inventory.can_unlock_cargo_row(captain) + else: + _label("Wszystkie rzędy ładowni odblokowane.",13,Color("849da5")) + for kind in ["weapon","extension"]: + var count: int = inventory.unlocked_weapon_slots if kind == "weapon" else inventory.unlocked_extension_slots + var limit: int = inventory.WEAPON_SLOT_COUNT if kind == "weapon" else inventory.EXTENSION_SLOT_COUNT + var title := "BRONI" if kind == "weapon" else "ROZSZERZENIA" + _label("Sloty %s: %d / %d" % [title.to_lower(),count,limit],14) + if count < limit: + var unlock := UI.button(_content,"ODBLOKUJ SLOT %s · 10 żelaza" % title,_unlock_ship_slot.bind(kind)) + unlock.disabled = not inventory.can_unlock_slot(kind,captain) + else: + _label("Wszystkie sloty odblokowane.",13,Color("849da5")) + +func _unlock_ship_slot(kind: String) -> void: + if is_instance_valid(inventory): inventory.unlock_slot(kind,captain) + _refresh() + +func _build_storage() -> void: + if not deck.is_built("expansion_3"): + _label("SKŁAD MODUŁÓW W REMONCIE",19,Color("e0b16a")) + _label("Zbuduj skład modułów, aby przechowywać wyposażenie na frachtowcu. Budowa jest teraz bezpłatna.") + UI.button(_content,"ZBUDUJ SKŁAD · BEZ KOSZTÓW",_construct_room.bind("expansion_3")) + return + if not is_instance_valid(inventory): + _label("Zadokuj swoim statkiem, aby przenosić wyposażenie.") + return + _label("Przechowuj moduły, broń i rozszerzenia. Wybierz przedmiot, aby przenieść go między ładownią a magazynem. Zamontowane wyposażenie najpierw zdejmij do ładowni.",13) + var columns := HBoxContainer.new() + columns.add_theme_constant_override("separation",18) + _content.add_child(columns) + var cargo_column := VBoxContainer.new() + cargo_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL + cargo_column.size_flags_stretch_ratio = 1 + columns.add_child(cargo_column) + var storage_column := VBoxContainer.new() + storage_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL + storage_column.size_flags_stretch_ratio = 1 + columns.add_child(storage_column) + UI.label(cargo_column,"STATEK · %d / %d" % [inventory.get_cargo_used(),inventory.get_cargo_capacity()],16,UI.CYAN) + var storage: Array = captain.expedition.freighter_storage + UI.label(storage_column,"FRACHTOWIEC · %d" % storage.size(),16,UI.CYAN) + var used := 0 + for index in inventory.get_cargo_capacity(): + var item: ItemInstance = inventory.get_item("cargo",index) + if item == null: continue + used += 1 + _storage_card(cargo_column,item,"ODŁÓŻ →",_transfer_storage.bind(false,index,item)) + if used == 0: UI.label(cargo_column,"Ładownia jest pusta.",13,Color("849da5")) + for index in storage.size(): + var item: ItemInstance = storage[index] + var button := _storage_card(storage_column,item,"← ODBIERZ",_transfer_storage.bind(true,index,item)) + button.disabled = inventory.get_cargo_used() >= inventory.get_cargo_capacity() + if storage.is_empty(): UI.label(storage_column,"Magazyn jest pusty.",13,Color("849da5")) + if inventory.get_cargo_used() >= inventory.get_cargo_capacity(): + _label("Ładownia statku jest pełna. Odłóż przedmiot lub odblokuj kolejny rząd w hangarze.",13,Color("e0b16a")) + +func _storage_card(parent: Control, item: ItemInstance, action: String, callback: Callable) -> Button: + var card := UI.panel(parent) + var stack := VBoxContainer.new() + card.add_child(stack) + var row := HBoxContainer.new() + stack.add_child(row) + var icon := TextureRect.new() + icon.custom_minimum_size = Vector2(38,38) + icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon.texture = item.definition.icon + row.add_child(icon) + var title := UI.label(row,"%s · +%d" % [item.definition.display_name,item.item_level],13,item.get_type_color()) + title.size_flags_horizontal = Control.SIZE_EXPAND_FILL + title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + card.tooltip_text = item.get_tooltip_text() + return UI.button(stack,action,callback) + +func _transfer_storage(retrieve: bool, index: int, expected: ItemInstance) -> void: + if not is_instance_valid(inventory): return + if retrieve: inventory.retrieve_from_freighter(index,expected,captain) + else: inventory.store_on_freighter(index,expected,captain) + _refresh() + +func _build_workshop() -> void: + _label("FABRYKATOR / WYPOSAŻENIE KAPITANA",13,Color("8bd9d0")) + _label("Każdy poziom wyposażenia usuwa 2 pp odpowiadającego mu zagrożenia. L50 zapewnia pełną ochronę tej składowej.",13) + for kind in GEAR.KINDS: + var card := UI.panel(_content) + var row := HBoxContainer.new() + row.add_theme_constant_override("separation",12) + card.add_child(row) + var icon := TextureRect.new() + icon.texture = GEAR.icon(kind) + icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon.custom_minimum_size = Vector2(46,46) + row.add_child(icon) + var column := VBoxContainer.new() + column.size_flags_horizontal = Control.SIZE_EXPAND_FILL + row.add_child(column) + var title := UI.label(column,"%s · L%d" % [GEAR.NAMES[kind],GEAR.next_level(captain,kind)],15,Color("e4e8e5")) + title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + var recipe := UI.label(column,GEAR.recipe_text(captain,kind),12,Color("a1b3b8")) + recipe.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + var build := UI.button(column,"WYTWÓRZ I ZAŁÓŻ",_craft.bind(kind)) + build.add_theme_font_size_override("font_size",13) + build.disabled = not GEAR.can_craft(captain,kind) + UI.button(_content,"POSIADANE WYPOSAŻENIE "+("−" if _owned_open else "+"),func(): + _owned_open = not _owned_open + _refresh()) + if _owned_open: for gear in captain.gear_items: var equipped: bool = captain.gear_slots.get(gear.kind,-1) == gear.uid - UI.button(_content, "%s · poziom %d%s" % [GEAR.NAMES[gear.kind],gear.level," [ZAŁOŻONE]" if equipped else " — ZAŁÓŻ"], _equip.bind(gear.kind,gear.uid)).disabled = equipped - var stock := UI.label(_content, "ZASOBY: " + UI.material_text(captain.minerals) + " · Części: %d" % captain.parts, 13) - stock.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - else: - UI.label(_content, "LABORATORIUM / ARCHIWUM", 24, UI.CYAN) - UI.label(_content, "ZESKANOWANE PLANETY: %d" % progress.scans.size(), 17) - for profile in progress.scans.values(): - UI.label(_content, "%s · tlen %d%% · %d°C · flora %d" % [profile.name,profile.oxygen,profile.temperature,profile.flora], 15) - if progress.scans.is_empty(): - UI.label(_content, "Podleć do planety earthlike i wykonaj skan [F].", 15) - UI.label(_content, "ODZYSKANE ARCHIWA", 18, UI.CYAN) - for key in progress.research_records: - UI.label(_content, "%s ×%d" % [key,progress.research_records[key]], 15) - UI.label(_content, "Archiwa są przechowywane na przyszłe badania technologii.", 14) + var label_text := "%s · L%d%s" % [GEAR.NAMES[gear.kind],gear.level," [ZAŁOŻONE]" if equipped else ""] + var button := UI.button(_content,label_text,_equip.bind(gear.kind,gear.uid)) + button.add_theme_font_size_override("font_size",13) + button.disabled = equipped + _label("ZASOBY: "+UI.material_text(captain.minerals),12,Color("819ca5")) + +func _build_command() -> void: + var progress: Resource = captain.expedition + _label("MOSTEK / SYSTEMY NAWIGACYJNE",13,Color("8bd9d0")) + _label("Łączność z twoim statkiem jest stabilna. Fregata pozostaje gotowa do przejścia do kolejnego układu.") + _label("Zeskanowane planety: %d" % progress.scans.size(),16) + _label("ODZYSKANE ARCHIWA",15,UI.CYAN) + if progress.research_records.is_empty(): + _label("Brak odzyskanych zapisów.",13,Color("819ca5")) + for key in progress.research_records: + _label("%s ×%d" % [key,progress.research_records[key]],13) + _label("Rozbudowa centrum dowodzenia oraz pozostałych sekcji będzie dostępna później.",13,Color("bc9e72")) func _craft(kind: String) -> void: var gear: Dictionary = GEAR.craft(captain,kind) diff --git a/scripts/planets/orbital_contact_range.gd b/scripts/planets/orbital_contact_range.gd new file mode 100644 index 0000000..176529b --- /dev/null +++ b/scripts/planets/orbital_contact_range.gd @@ -0,0 +1,10 @@ +extends RefCounted +const PLANET_RADIUS_RATIO := 0.92 +const FREIGHTER_HALF_SIZE := Vector2(62,131) + +static func at_planet(player: Node2D, planet: Node2D) -> bool: + return player.global_position.distance_to(planet.global_position) <= float(planet.get("radius"))*PLANET_RADIUS_RATIO + +static func at_freighter(player: Node2D, freighter: Node2D) -> bool: + var relative := (player.global_position-freighter.global_position)/FREIGHTER_HALF_SIZE + return relative.length_squared() <= 1.0 diff --git a/scripts/planets/orbital_contact_range.gd.uid b/scripts/planets/orbital_contact_range.gd.uid new file mode 100644 index 0000000..5f0f022 --- /dev/null +++ b/scripts/planets/orbital_contact_range.gd.uid @@ -0,0 +1 @@ +uid://s446y2u1fbtl diff --git a/scripts/planets/planet_progress.gd b/scripts/planets/planet_progress.gd index ca4c9b5..48b8837 100644 --- a/scripts/planets/planet_progress.gd +++ b/scripts/planets/planet_progress.gd @@ -7,6 +7,8 @@ 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 freighter_rooms: Dictionary = {} +@export var freighter_storage: Array[Resource] = [] @export var delivered_missiles := 0 var cargo_credits := 0 var cargo_parts := 0 diff --git a/scripts/planets/planet_rewards.gd.uid b/scripts/planets/planet_rewards.gd.uid new file mode 100644 index 0000000..283da2c --- /dev/null +++ b/scripts/planets/planet_rewards.gd.uid @@ -0,0 +1 @@ +uid://pa1qyqutky6r diff --git a/scripts/planets/surface_clouds.gd b/scripts/planets/surface_clouds.gd new file mode 100644 index 0000000..33ac8a4 --- /dev/null +++ b/scripts/planets/surface_clouds.gd @@ -0,0 +1,52 @@ +extends Node2D +## Terrain scrolls at 1x; this elevated mist moves at 1.22x and 1.34x. +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 + +func _ready() -> void: + texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS + shadows = Node2D.new() + shadows.name = "CloudShadows" + shadows.z_index = 5 + add_child(shadows) + clouds = Node2D.new() + clouds.name = "AboveLander" + clouds.z_index = 70 + add_child(clouds) + var rng := RandomNumberGenerator.new() + 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)}) + _process(0) + +func _process(delta: float) -> void: + _time += delta + 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.mist.position = location + bank.shadow.position = location+Vector2(35,45) diff --git a/scripts/planets/surface_clouds.gd.uid b/scripts/planets/surface_clouds.gd.uid new file mode 100644 index 0000000..fc8b0c7 --- /dev/null +++ b/scripts/planets/surface_clouds.gd.uid @@ -0,0 +1 @@ +uid://c072f72jgfc5h diff --git a/scripts/planets/surface_events.gd.uid b/scripts/planets/surface_events.gd.uid new file mode 100644 index 0000000..83a6ddb --- /dev/null +++ b/scripts/planets/surface_events.gd.uid @@ -0,0 +1 @@ +uid://dfkiiqo7qc66i diff --git a/scripts/planets/surface_generator.gd b/scripts/planets/surface_generator.gd index 11a6ad4..c7fd15f 100644 --- a/scripts/planets/surface_generator.gd +++ b/scripts/planets/surface_generator.gd @@ -3,6 +3,7 @@ const LANDSCAPE := preload("res://scripts/planets/surface_landscape.gd") const GRID := 96 const CELL := 40.0 const WORLD_SIZE := GRID * CELL +const EXTRA_STRUCTURE_CHANCE := 0.25 static func generate(seed_value: int, profile: Dictionary) -> Dictionary: var rng := RandomNumberGenerator.new() @@ -48,8 +49,11 @@ static func generate(seed_value: int, profile: Dictionary) -> Dictionary: if point.length() > 200 and heights[gy*GRID+gx] > 0.30: rocks.append({"position":point,"size":rng.randf_range(14,45),"rotation":rng.randf_range(-PI,PI)}) var pois: Array[Dictionary] = [] - for index in 8: - var kind: String = ["mine", "ruins", "deposit"][index % 3] + var kinds: Array[String] = ["mine","ruins","deposit","deposit"] + if rng.randf() < EXTRA_STRUCTURE_CHANCE: kinds.append("mine") + if rng.randf() < EXTRA_STRUCTURE_CHANCE: kinds.append("ruins") + for index in kinds.size(): + var kind: String = kinds[index] var chosen := Vector2.ZERO var found := false for attempt in 1500: @@ -69,7 +73,7 @@ static func generate(seed_value: int, profile: Dictionary) -> Dictionary: break if not found: # A lander can cross every terrain; a remote fallback never traps it. - chosen = Vector2.from_angle(index * TAU / 8) * 1250 + chosen = Vector2.from_angle(index * TAU / kinds.size()) * 1250 pois.append({"id": index, "kind": kind, "position": chosen, "stage": 0, "complete": false, "discovered": false}) # Clear vegetation around explorable structures so entrances stay readable. for poi in pois: diff --git a/scripts/planets/surface_mountains.gd b/scripts/planets/surface_mountains.gd new file mode 100644 index 0000000..88a7d43 --- /dev/null +++ b/scripts/planets/surface_mountains.gd @@ -0,0 +1,18 @@ +extends Node2D +var data: Dictionary +const TEXTURE := preload("res://assets/planets/mountain.png") + +func _ready() -> void: + texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS + var blend := ShaderMaterial.new() + blend.shader = preload("res://resources/effects/mountain_blend.gdshader") + blend.set_shader_parameter("ground_tint",(data.landscape.high as Color).lerp(data.landscape.low,0.35)) + blend.set_shader_parameter("rock_tint",data.landscape.rock) + material = blend + +func _draw() -> void: + for mountain in data.mountains: + draw_set_transform(mountain.position,mountain.rotation) + var extent := Vector2(mountain.size,mountain.size*TEXTURE.get_height()/TEXTURE.get_width()) + draw_texture_rect(TEXTURE,Rect2(-extent*0.5,extent),false) + draw_set_transform(Vector2.ZERO) diff --git a/scripts/planets/surface_mountains.gd.uid b/scripts/planets/surface_mountains.gd.uid new file mode 100644 index 0000000..a0db1eb --- /dev/null +++ b/scripts/planets/surface_mountains.gd.uid @@ -0,0 +1 @@ +uid://b8m1xapq1ohwd diff --git a/scripts/planets/surface_scenery.gd b/scripts/planets/surface_scenery.gd index 941a658..6639434 100644 --- a/scripts/planets/surface_scenery.gd +++ b/scripts/planets/surface_scenery.gd @@ -15,11 +15,12 @@ static func generate(data: Dictionary, rng: RandomNumberGenerator) -> void: data.structures.append({"kind":kind,"position":position,"size":width,"rotation":rng.randf_range(-PI,PI)}) var event_rng := RandomNumberGenerator.new() event_rng.seed = int(data.seed) ^ 0x45564e54 - if event_rng.randf() < 0.5: - var position := find_site(data,event_rng,60) - if position != Vector2.INF: - 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}) + var position := find_event_site(data,event_rng) + 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.rocks = data.rocks.filter(func(prop): return prop.position.distance_to(position) > 80) var clearings: Array = data.structures.duplicate() for clearing in clearings: data.trees = data.trees.filter(func(prop): return prop.position.distance_to(clearing.position) > float(clearing.size)*0.6+float(prop.size)*0.3) @@ -57,3 +58,24 @@ static func find_site(data: Dictionary, rng: RandomNumberGenerator, radius: floa if good: return point return Vector2.INF + +static func find_event_site(data: Dictionary, rng: RandomNumberGenerator) -> Vector2: + var preferred := find_site(data,rng,60) + if preferred != Vector2.INF: return preferred + # Lander movement supports every terrain. Guarantee one encounter even on + # maps without flat ground, away from the landing pad and other locations. + var chosen := Vector2(1200,1200) + var best_clearance := -INF + for y in range(-1600,1601,160): + for x in range(-1600,1601,160): + var point := Vector2(x,y) + if point.length() < 400: continue + var clearance := point.length()-310 + for poi in data.pois: + clearance = minf(clearance,point.distance_to(poi.position)-210) + for structure in data.structures: + clearance = minf(clearance,point.distance_to(structure.position)-float(structure.size)*0.65-120) + if clearance > best_clearance: + best_clearance = clearance + chosen = point + return chosen diff --git a/scripts/planets/surface_screen.gd b/scripts/planets/surface_screen.gd index a46fd5c..bdcc0ca 100644 --- a/scripts/planets/surface_screen.gd +++ b/scripts/planets/surface_screen.gd @@ -86,6 +86,11 @@ func _ready() -> void: camera.limit_right = 1920 camera.limit_bottom = 1920 viewport.add_child(camera) + var atmosphere := Node2D.new() + atmosphere.name = "SurfaceAtmosphere" + atmosphere.set_script(preload("res://scripts/planets/surface_clouds.gd")) + atmosphere.seed_value = progress.visit_seed + viewport.add_child(atmosphere) resized.connect(_resize_surface_viewport) var info := UI.panel(self, Vector2(440, 0)) info.position = Vector2(24, 24) diff --git a/scripts/planets/surface_world.gd b/scripts/planets/surface_world.gd index 1b7443e..5556b6f 100644 --- a/scripts/planets/surface_world.gd +++ b/scripts/planets/surface_world.gd @@ -6,7 +6,6 @@ var data: Dictionary var terrain: ImageTexture var _nature: Array[AtlasTexture] = [] var _tree: Texture2D -var _mountain: Texture2D var _poi_sprites: Dictionary = {} var _poi_labels: Dictionary = {} var _event_nodes: Array[Dictionary] = [] @@ -49,7 +48,12 @@ func _ready() -> void: tile.filter_clip = true _nature.append(tile) _tree = load("res://assets/planets/tree.png") - _mountain = load("res://assets/planets/mountain.png") + var mountains := Node2D.new() + mountains.name = "Mountains" + mountains.set_script(preload("res://scripts/planets/surface_mountains.gd")) + mountains.data = data + mountains.z_index = -1 + add_child(mountains) for poi in data.pois: var sprite := Sprite2D.new() sprite.texture = load("res://assets/planets/%s.png" % ("ruins" if poi.kind == "ruins" else "mine")) if poi.kind != "deposit" else load("res://assets/icons/resources/titanium.png") @@ -130,8 +134,6 @@ func _draw() -> void: for detail in data.get("details", []): var shade := float(detail.shade) _draw_prop(_nature[int(detail.variant)], detail.position, detail.size, detail.rotation, Color(shade,shade,shade)) - for mountain in data.mountains: - _draw_prop(_mountain, mountain.position, mountain.size, mountain.rotation, Color.WHITE) for rock in data.rocks: _draw_prop(_nature[int(rock.get("variant",4))],rock.position,rock.size,rock.rotation,Color.WHITE) for tree in data.trees: diff --git a/scripts/ui/equipment_slot_view.gd b/scripts/ui/equipment_slot_view.gd index 0c8099d..7f88dcc 100644 --- a/scripts/ui/equipment_slot_view.gd +++ b/scripts/ui/equipment_slot_view.gd @@ -101,6 +101,14 @@ func _refresh() -> void: return var item: ItemInstance = _inventory.get_item(slot_kind, slot_index) _apply_slot_style(item) + if not _inventory.is_slot_unlocked(slot_kind,slot_index): + _icon.texture = null + 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." + _update_salvage_visibility() + return _icon.texture = item.definition.icon if item != null and item.definition != null else _empty_icon() _icon.modulate = Color(1, 1, 1, 1.0 if item != null else 0.16) slot_label.visible = _icon.texture == null diff --git a/scripts/ui/flight_cockpit.gd b/scripts/ui/flight_cockpit.gd index d08af94..778f41a 100644 --- a/scripts/ui/flight_cockpit.gd +++ b/scripts/ui/flight_cockpit.gd @@ -65,7 +65,7 @@ func _draw() -> void: draw_line(Vector2(x + cell, 14), Vector2(x + cell, 45), Color("2b4354"), 1) var card := Rect2(20 + index * 60, 12, 52, 52) var slot_index: int = WEAPON_DISPLAY_ORDER[index] - var item := _inventory.weapon_slots[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] @@ -73,7 +73,7 @@ func _draw() -> void: if item != null and item.definition.icon != null: draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(9, 16), Vector2(34, 34)), false) else: - _text("—", 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, 36), card.size.x, 14, Color("637d90")) func _card_style(color: Color) -> StyleBoxFlat: var style := StyleBoxFlat.new() diff --git a/scripts/ui/orbital_contact_style.gd b/scripts/ui/orbital_contact_style.gd new file mode 100644 index 0000000..f309b46 --- /dev/null +++ b/scripts/ui/orbital_contact_style.gd @@ -0,0 +1,72 @@ +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.border_color = Color(accent,0.55) + style.set_border_width_all(1) + style.border_width_top = 2 + style.set_corner_radius_all(7) + style.content_margin_left = 12 + style.content_margin_right = 12 + style.content_margin_top = 10 + style.content_margin_bottom = 10 + style.shadow_color = Color(0,0,0,0.28) + style.shadow_size = 7 + style.shadow_offset = Vector2(0,3) + return style + +static func compact_button(button: Button, accent: Color) -> void: + preload("res://scripts/ui/hud_button_style.gd").apply(button,accent) + button.custom_minimum_size.y = 30 + 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.content_margin_top = 4 + style.content_margin_bottom = 4 + style.content_margin_left = 9 + style.content_margin_right = 9 + style.shadow_size = 0 + style.set_corner_radius_all(4) + button.add_theme_stylebox_override(state,style) + +static func hud_obstacles(hud: Node) -> Array[Rect2]: + var boxes: Array[Rect2] = [] + if hud == null: return boxes + for name in ["CaptainPanel","CaptainEquipment","MissionObjectives","ShipDrawer","PassiveCaptainPanel","PassiveShipPanel"]: + var control := hud.get_node_or_null(NodePath(name)) as Control + if control != null and control.is_visible_in_tree(): boxes.append(control.get_global_rect().grow(6)) + return boxes + +static func beside(center: Vector2, radius: float, extent: Vector2, viewport: Vector2, obstacles: Array[Rect2] = [], prefer_right := true, vertical_radius := -1.0) -> Vector2: + var gap := 14.0 + var vertical := radius if vertical_radius < 0 else vertical_radius + var right := center + Vector2(radius+gap,-extent.y*0.5) + var left := center - Vector2(radius+gap+extent.x,extent.y*0.5) + var candidates: Array[Vector2] = [right,left] + if not prefer_right: candidates.reverse() + candidates.append(center+Vector2(-extent.x*0.5,-vertical-gap-extent.y)) + candidates.append(center+Vector2(-extent.x*0.5,vertical+gap)) + # Additional lanes prevent two cards from clipping one another's headers. + for obstacle in obstacles: + candidates.append(Vector2(center.x-extent.x*0.5,obstacle.position.y-gap-extent.y)) + candidates.append(Vector2(center.x-extent.x*0.5,obstacle.end.y+gap)) + var chosen := Vector2.ZERO + var best := INF + var low := Vector2(10,88) + var high := Vector2(maxf(low.x,viewport.x-extent.x-10),maxf(low.y,viewport.y-extent.y-118)) + for index in candidates.size(): + var candidate := candidates[index] + var clamped := candidate.clamp(low,high) + var box := Rect2(clamped,extent) + var score := candidate.distance_to(clamped) + index*8.0 + # Avoid covering the object if an edge forces the card to change sides. + var object_box := Rect2(center-Vector2(radius,vertical),Vector2(radius,vertical)*2) + if box.intersects(object_box): score += box.intersection(object_box).get_area()*0.1 + for obstacle in obstacles: + if box.intersects(obstacle): score += box.intersection(obstacle).get_area() + if score < best: + best = score + chosen = clamped + return chosen diff --git a/scripts/ui/orbital_contact_style.gd.uid b/scripts/ui/orbital_contact_style.gd.uid new file mode 100644 index 0000000..c76bffd --- /dev/null +++ b/scripts/ui/orbital_contact_style.gd.uid @@ -0,0 +1 @@ +uid://brwxl670u7wd3 diff --git a/scripts/ui/planet_services_menu.gd b/scripts/ui/planet_services_menu.gd index 4639c61..ecadeaf 100644 --- a/scripts/ui/planet_services_menu.gd +++ b/scripts/ui/planet_services_menu.gd @@ -4,6 +4,7 @@ signal next_level_requested const BUTTON_STYLE := preload("res://scripts/ui/hud_button_style.gd") const CREDIT_ICON := preload("res://assets/icons/resources/credits.svg") +const CONTACT := preload("res://scripts/ui/orbital_contact_style.gd") @onready var next_button: Button = $Center/Panel/Contents/NextButton @onready var buy_ammunition_button: Button = $Center/Panel/Contents/BuyAmmunitionButton @onready var reset_skills_button: Button = $Center/Panel/Contents/ResetSkillsButton @@ -48,7 +49,12 @@ func _ready() -> void: func _build_compact_shop() -> void: var contents := $Center/Panel/Contents - contents.add_theme_constant_override("separation", 7) + panel.custom_minimum_size.x = 300 + panel.add_theme_stylebox_override("panel",CONTACT.panel_style(Color("78d7be"))) + contents.get_node("Title").text = "● STACJA / ZAOPATRZENIE" + contents.get_node("Title").horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT + contents.get_node("Title").add_theme_font_size_override("font_size",11) + contents.add_theme_constant_override("separation", 5) status_label.add_theme_font_size_override("font_size", 10) status_label.add_theme_color_override("font_color", Color("86b7aa")) services_label.add_theme_font_size_override("font_size", 11) @@ -77,7 +83,7 @@ func _build_compact_shop() -> void: _add_offer(offers, _gamma_buy, "irradiated_ammunition", "Radiacyjna", 10, Color("add580")) _add_offer(offers, _missile_button, "missile", "Rakieta", 1, Color("82cddd")) BUTTON_STYLE.apply(next_button, Color("78d7be")) - next_button.custom_minimum_size = Vector2(0, 34) + next_button.custom_minimum_size = Vector2(0, 30) next_button.add_theme_font_size_override("font_size", 11) next_button.icon = preload("res://assets/icons/extensions/teleport_art.png") next_button.expand_icon = true @@ -87,10 +93,10 @@ func _build_compact_shop() -> void: func _add_offer(offers: HBoxContainer, button: Button, item_id: String, caption: String, amount: int, accent: Color) -> void: var card := PanelContainer.new() card.name = item_id.capitalize().replace(" ", "") + "Offer" - card.custom_minimum_size.x = 94 + card.custom_minimum_size.x = 86 card.size_flags_horizontal = Control.SIZE_EXPAND_FILL var style := StyleBoxFlat.new() - style.bg_color = Color("101e2a") + style.bg_color = Color(0.035,0.075,0.105,0.60) style.border_color = accent.darkened(0.65) style.set_border_width_all(1) style.border_width_top = 2 @@ -103,7 +109,7 @@ func _add_offer(offers: HBoxContainer, button: Button, item_id: String, caption: card.add_child(column) var icon := TextureRect.new() icon.texture = load("res://assets/icons/resources/%s.png" % item_id) - icon.custom_minimum_size = Vector2(36, 36) + icon.custom_minimum_size = Vector2(30, 30) icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED icon.mouse_filter = Control.MOUSE_FILTER_IGNORE @@ -164,17 +170,14 @@ func _position_at_planet() -> void: return if not is_instance_valid(planet): return - var canvas := get_viewport().get_canvas_transform() - var planet_screen := canvas * planet.global_position + var canvas := planet.get_global_transform_with_canvas() + var planet_screen := canvas.origin var planet_radius := float(planet.get("radius")) * canvas.x.length() size = panel.get_combined_minimum_size() var viewport_size := get_viewport_rect().size var sidebar := get_parent().get_node_or_null("ShipDrawer") as Control var screen_right := minf(viewport_size.x - 8.0, sidebar.get_global_rect().position.x - 8.0) if sidebar != null and sidebar.visible else viewport_size.x - 8.0 - var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5) - if target.x + size.x > screen_right: - target.x = planet_screen.x - planet_radius - 24.0 - size.x - position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 150.0))) + position = CONTACT.beside(planet_screen,planet_radius,size,Vector2(screen_right+8,viewport_size.y),CONTACT.hud_obstacles(get_parent()),false) func _refresh_ammunition_service() -> void: var ordinary_cost := _inventory.get_ammunition_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level)) diff --git a/scripts/ui/player_guide.gd b/scripts/ui/player_guide.gd index 40908e3..c47bbbf 100644 --- a/scripts/ui/player_guide.gd +++ b/scripts/ui/player_guide.gd @@ -7,7 +7,7 @@ const PAGES := [ ["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 — przycisk TWÓRZ[/b][/color]\nZ minerałów wytworzysz części, amunicję, rakiety i powerbanki. Receptura pokazuje wymagane składniki oraz ilość produktu.\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: 3 bronie, 5 modułów i 5 rozszerzeń. 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."] + ["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 wytwarza sprzęt kapitana, a laboratorium przechowuje skany i archiwa.\n\nKapitan zaczyna z podstawowym systemem oddychania, skafandrem i bronią ręczną. Kolejne poziomy tworzysz w warsztacie; sprzęt zmienisz także w panelu pod kapitanem. 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]"] ] var _panel: PanelContainer diff --git a/scripts/ui/ship_inventory_panel.gd b/scripts/ui/ship_inventory_panel.gd index 7dd534b..4cd8462 100644 --- a/scripts/ui/ship_inventory_panel.gd +++ b/scripts/ui/ship_inventory_panel.gd @@ -42,7 +42,7 @@ func _refresh_title() -> void: _resource_cards[key].set_amount(float(GameState.captain.minerals.get(key, 0))) _resource_cards["parts"].set_amount(GameState.captain.parts) if _inventory: - title_label.text = "MAGAZYN · %d / %d" % [_inventory.get_cargo_used(), CARGO_SIZE] + title_label.text = "MAGAZYN · %d / %d" % [_inventory.get_cargo_used(), _inventory.get_cargo_capacity()] _resource_cards["ammunition"].set_amount(_inventory.ammunition) _resource_cards["irradiated_ammunition"].set_amount(_inventory.irradiated_ammunition) _resource_cards["missile"].set_amount(_inventory.get_missile_count()) diff --git a/tests/abilities/passive_extensions_test.gd b/tests/abilities/passive_extensions_test.gd index 9263ae5..a46a58d 100644 --- a/tests/abilities/passive_extensions_test.gd +++ b/tests/abilities/passive_extensions_test.gd @@ -45,6 +45,7 @@ func _ready() -> void: ship.get_node("WeaponController").set_physics_process(false) ship.get_node("ExtensionSystems").set_physics_process(false) inventory = ship.get_node("ShipInventory") + inventory.unlocked_extension_slots = ShipInventory.EXTENSION_SLOT_COUNT # This fixture tests all passive effects together. var recycler := equip("recycler", 0, 0.5) var virus := equip("virus", 1, 1) var armor := equip("titanium_armor", 2, 5) diff --git a/tests/abilities/tactical_extensions_test.gd b/tests/abilities/tactical_extensions_test.gd index 992908c..3f4c50b 100644 --- a/tests/abilities/tactical_extensions_test.gd +++ b/tests/abilities/tactical_extensions_test.gd @@ -24,6 +24,8 @@ func _ready() -> void: var systems := ship.get_node("ExtensionSystems") systems.set_physics_process(false) inventory = ship.get_node("ShipInventory") as ShipInventory + inventory.unlocked_extension_slots = ShipInventory.EXTENSION_SLOT_COUNT # Full-loadout ability fixture. + inventory.unlocked_weapon_slots = ShipInventory.WEAPON_SLOT_COUNT for index in IDS.size(): equip(IDS[index], index) var enemy := ENEMY.instantiate() as CharacterBody2D diff --git a/tests/levels/landscape_generation_test.gd b/tests/levels/landscape_generation_test.gd index b0ca07b..68003a4 100644 --- a/tests/levels/landscape_generation_test.gd +++ b/tests/levels/landscape_generation_test.gd @@ -8,7 +8,7 @@ func _ready() -> void: profile.temperature = 70 if index==4 else (-30 if index==5 else 20) var data: Dictionary = GENERATOR.generate(200+index,profile) styles[data.landscape.name] = true - assert(data.pois.size() == 8 and data.rocks.size() > 0) + assert(data.pois.size() >= 4 and data.pois.size() <= 6 and data.rocks.size() > 0) assert(not data.has("rivers") and not data.has("river")) assert(data.structures.size() > 0) for structure in data.structures: diff --git a/tests/levels/planet_expeditions_test.gd b/tests/levels/planet_expeditions_test.gd index aaa9902..44d9314 100644 --- a/tests/levels/planet_expeditions_test.gd +++ b/tests/levels/planet_expeditions_test.gd @@ -49,7 +49,7 @@ func _ready() -> void: assert(GEAR.equip(captain,"breathing",crafted.uid)) assert(GEAR.level(captain,"breathing") == 2) var world: Dictionary = SURFACE.generate(11447,profile) - assert(world.pois.size() == 8 and world.trees.size() > 0 and world.mountains.size() > 0 and world.structures.size() > 0) + assert(world.pois.size() >= 4 and world.pois.size() <= 6 and world.trees.size() > 0 and world.mountains.size() > 0 and world.structures.size() > 0) assert(SURFACE.generate(11447,profile).pois == world.pois) assert(SURFACE.generate(11448,profile).pois != world.pois) for seed_value in 100: @@ -119,7 +119,7 @@ func _ready() -> void: manager.scan_nearby() manager.land_nearby() assert(get_tree().paused and GameState.captain.expedition.active) - assert(manager.screen.world.data.pois.size() == 8) + assert(manager.screen.world.data.pois.size() >= 4 and manager.screen.world.data.pois.size() <= 6) manager.screen.lander.position = manager.screen.world.data.pois[0].position manager.screen._poi = manager.screen.world.data.pois[0] manager.screen._show_poi() diff --git a/tests/levels/planet_prompt_test.gd b/tests/levels/planet_prompt_test.gd index 8875777..7c97d4b 100644 --- a/tests/levels/planet_prompt_test.gd +++ b/tests/levels/planet_prompt_test.gd @@ -7,9 +7,14 @@ func settle() -> void: func check_hint(expected: String) -> void: await settle() + game.player.reset_physics_interpolation() + game.player.get_node("Camera2D").force_update_scroll() + await get_tree().physics_frame + await RenderingServer.frame_post_draw + manager._layout_prompt() assert(manager._prompt.visible) assert(manager._text.text.contains(expected)) - assert(manager._prompt.size.y < 450) + assert(manager._prompt.size.y < 260 and manager._prompt.size.x <= 320) assert(manager._prompt.get_global_rect().encloses(manager._text.get_global_rect())) if manager._land_button.visible: assert(manager._prompt.get_global_rect().encloses(manager._land_button.get_global_rect())) @@ -21,6 +26,19 @@ func _ready() -> void: add_child(game) await settle() manager = game.get_node("PlanetExpeditions") + var sprite: Sprite2D = manager.freighter.get_child(0) + assert(is_equal_approx(maxf(sprite.texture.get_width(),sprite.texture.get_height())*sprite.scale.x,285.0)) + var style := manager._prompt.get_theme_stylebox("panel") as StyleBoxFlat + assert(style.bg_color.a > 0.75 and style.bg_color.a < 0.9) + var contact := preload("res://scripts/ui/orbital_contact_style.gd") + var extent := Vector2(300,180) + var viewport := Vector2(1280,720) + var center := Vector2(640,360) + assert(contact.beside(center,90,extent,viewport) == Vector2(744,270)) + var obstacle: Array[Rect2] = [Rect2(744,270,300,180)] + assert(contact.beside(center,90,extent,viewport,obstacle).x < center.x) + for edge in [Vector2(35,100),Vector2(1245,100),Vector2(35,620),Vector2(1245,620)]: + assert(Rect2(Vector2.ZERO,viewport).encloses(Rect2(contact.beside(edge,90,extent,viewport),extent))) for enemy in get_tree().get_nodes_in_group("enemies"): enemy.position = Vector2(-9999,-9999) game.player.position = Vector2(10000,10000) @@ -62,6 +80,20 @@ func _ready() -> void: manager.scan_nearby() manager._process(0) await check_hint("ŚREDNIA SZANSA POI") + var camera: Camera2D = game.player.get_node("Camera2D") + var previous_canvas := get_viewport().canvas_transform + camera.enabled = false + get_viewport().canvas_transform = Transform2D(0,Vector2(640,360)-game.protected_planet.global_position) + manager._layout_prompt() + var previous_position: Vector2 = manager._prompt.position + get_viewport().canvas_transform = get_viewport().canvas_transform.translated(Vector2(70,0)) + manager._layout_prompt() + assert(manager._prompt.position.distance_to(previous_position) > 10,"Contact card follows the camera while text stays unchanged") + get_viewport().canvas_transform = previous_canvas + camera.enabled = true + camera.force_update_scroll() + await settle() + manager._layout_prompt() if "--capture-preview" in OS.get_cmdline_user_args(): await RenderingServer.frame_post_draw get_viewport().get_texture().get_image().save_png("res://artifacts/planet_scan_stats.png") diff --git a/tests/levels/planet_reward_scaling_test.gd.uid b/tests/levels/planet_reward_scaling_test.gd.uid new file mode 100644 index 0000000..d5fb598 --- /dev/null +++ b/tests/levels/planet_reward_scaling_test.gd.uid @@ -0,0 +1 @@ +uid://dt1nvfsx2vtpd diff --git a/tests/levels/planet_threats_test.gd.uid b/tests/levels/planet_threats_test.gd.uid new file mode 100644 index 0000000..918f39c --- /dev/null +++ b/tests/levels/planet_threats_test.gd.uid @@ -0,0 +1 @@ +uid://2oh5wfnwjf33 diff --git a/tests/levels/surface_events_test.gd b/tests/levels/surface_events_test.gd index 922ddcd..2ced4c1 100644 --- a/tests/levels/surface_events_test.gd +++ b/tests/levels/surface_events_test.gd @@ -163,7 +163,7 @@ func _ready() -> void: assert(rarities.size() == 5) assert(EVENTS._module(bonus_rng,1000,{"difficulty":1.0}).item_level == 1000) print("MODULE LOOT PASS: normal through legendary rarity, hard biome level +2..+10, decreasing exponential weights; histogram=",histogram) - # 50% roll, one marker maximum, all ten kinds on usable terrain. + # Exactly one guaranteed marker, all ten kinds on usable terrain. var data := GENERATOR.generate(200,profile) data.trees = [] data.rocks = [] @@ -177,11 +177,11 @@ func _ready() -> void: data.seed = index rng.seed = index SCENERY.generate(data,rng) - assert(data.events.size() <= 1) + assert(data.events.size() == 1) encounters += data.events.size() for spawned in data.events: assert(EVENTS.KINDS.has(spawned.kind)) counts[spawned.kind] = int(counts.get(spawned.kind,0))+1 - assert(encounters > 450 and encounters < 550 and counts.size() == 10) + assert(encounters == 1000 and counts.size() == 10) print("SURFACE EVENTS PASS: all 10 stories/actions, fixed offers, costs, discounts, scan stages, success/failure, evacuation, repair, safe return, destruction, one-time delivery. Spawn count / 1000: ",encounters,"; kinds: ",counts) get_tree().quit() diff --git a/tests/levels/surface_poi_counts_test.gd b/tests/levels/surface_poi_counts_test.gd new file mode 100644 index 0000000..816c038 --- /dev/null +++ b/tests/levels/surface_poi_counts_test.gd @@ -0,0 +1,35 @@ +extends Node +const GENERATOR := preload("res://scripts/planets/surface_generator.gd") +const SCENERY := preload("res://scripts/planets/surface_scenery.gd") + +func _ready() -> void: + var extra_mines := 0 + var extra_ruins := 0 + 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) + var counts := {"mine":0,"ruins":0,"deposit":0} + for poi in data.pois: counts[poi.kind] += 1 + assert(counts.mine in [1,2] and counts.ruins in [1,2]) + assert(counts.deposit == 2) + assert(data.events.size() == 1 and data.events[0].position.is_finite()) + assert(data.events[0].position.length() > 300) + extra_mines += int(counts.mine == 2) + extra_ruins += int(counts.ruins == 2) + if index == 0: + var repeated: Dictionary = GENERATOR.generate(500,profile) + assert(repeated.pois == data.pois and repeated.events == data.events) + # Most maps have one of each, with some maps containing a second. + assert(extra_mines > 4 and extra_mines < 30) + assert(extra_ruins > 4 and extra_ruins < 30) + # 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) + fallback.heights.fill(0.0) + var rng := RandomNumberGenerator.new() + rng.seed = 987 + 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, mines/ruins 1..2, two deposits, one guaranteed event, deterministic layout, no-flat-ground fallback; extra mines/ruins=",extra_mines,"/",extra_ruins) + get_tree().quit() diff --git a/tests/levels/surface_poi_counts_test.gd.uid b/tests/levels/surface_poi_counts_test.gd.uid new file mode 100644 index 0000000..6c539c5 --- /dev/null +++ b/tests/levels/surface_poi_counts_test.gd.uid @@ -0,0 +1 @@ +uid://cijsswd35dolt diff --git a/tests/levels/surface_poi_counts_test.tscn b/tests/levels/surface_poi_counts_test.tscn new file mode 100644 index 0000000..c0e4cf2 --- /dev/null +++ b/tests/levels/surface_poi_counts_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/levels/surface_poi_counts_test.gd" id="1"] +[node name="SurfacePoiCountsTest" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/freighter_interior_preview.gd b/tests/previews/freighter_interior_preview.gd new file mode 100644 index 0000000..a0f49e8 --- /dev/null +++ b/tests/previews/freighter_interior_preview.gd @@ -0,0 +1,159 @@ +extends Node +const GEAR := preload("res://scripts/planets/captain_equipment.gd") +var screen: Control + +func settle() -> void: + for frame in 5: + await get_tree().process_frame + await RenderingServer.frame_post_draw + +func capture(name: String) -> void: + await settle() + get_viewport().get_texture().get_image().save_png("res://artifacts/freighter_interior_%s.png" % name) + +func click_room(id: String) -> void: + var section: Dictionary = screen.deck.room(id) + var point: Vector2 = screen.deck.design_to_local((section.rect as Rect2).get_center()) + assert(screen.deck.section_at(point) == id) + var event := InputEventMouseButton.new() + event.button_index = MOUSE_BUTTON_LEFT + event.pressed = true + event.position = point + screen.deck._gui_input(event) + assert(screen._tab == id) + +func button_starting(text: String) -> Button: + for node in screen._content.find_children("*","Button",true,false): + if node.text.begins_with(text): + return node as Button + return null + +func _ready() -> void: + GameState.system_seed = 8428159 + GameState.selected_ship_path = "res://assets/Ships/player/bastion.png" + GameState.captain.parts = 100 + GameState.captain.credits = 2000 + for key in ["silicon","copper","nickel","iron","tungsten","titanium"]: + GameState.captain.minerals[key] = 500 + GameState.captain.expedition.lander_hp = 63 + GameState.captain.expedition.freighter_rooms.clear() + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + var manager := game.get_node("PlanetExpeditions") + assert(manager.freighter.z_index < game.player.z_index) + var music: AudioStreamPlayer = game.get_node("GameMusic") + assert(music.playing and not music.stream_paused) + var music_before := music.get_playback_position() + manager.open_freighter() + await get_tree().create_timer(0.18,true).timeout + assert(music.can_process() and music.playing and not music.stream_paused) + assert(music.get_playback_position() > music_before,"Music must continue from its current position during docking") + screen = manager.screen + assert(screen.scene_file_path == "res://scenes/planets/freighter_interior.tscn") + assert(get_tree().paused and game.player.is_docked) + assert(screen.deck.ship_texture == game.player.get_node("Sprite2D").texture) + assert(screen.deck.ship_name == "Bastion") + assert(screen.deck.ROOMS.size() == 11) + assert(screen.deck._art.get_image().has_mipmaps()) + var active := 0 + var upper_locked := 0 + var lower_locked := 0 + for section in screen.deck.ROOMS: + active += int(section.active) + upper_locked += int(str(section.id).begins_with("expansion")) + lower_locked += int(str(section.id).begins_with("cabin")) + var point: Vector2 = screen.deck.design_to_local((section.rect as Rect2).get_center()) + assert(screen.deck.section_at(point) == section.id) + assert(active == 2 and upper_locked == 3 and lower_locked == 5) + assert(not screen._drawer.visible) + var before: float = screen.deck._time + await capture("overview") + assert(screen.deck._time > before,"Deck lights must animate while space is paused") + click_room("workshop") + await capture("workshop") + assert(screen._drawer.get_global_rect().end.x <= get_viewport().get_visible_rect().size.x) + assert(screen._drawer.get_global_rect().end.y <= get_viewport().get_visible_rect().size.y) + var build := button_starting("WYTWÓRZ I ZAŁÓŻ") + assert(build != null and not build.disabled) + build.pressed.emit() + assert(GEAR.level(GameState.captain,"breathing") == 2) + assert(GameState.captain.parts == 90) + screen._close_section() + click_room("expansion_2") + await capture("renovation") + assert(button_starting("WYTWÓRZ") == null) + click_room("cabin_3") + assert(screen._drawer_title.text == "KAJUTA 03") + var escape := InputEventKey.new() + escape.pressed = true + escape.keycode = KEY_ESCAPE + screen._input(escape) + assert(not screen._drawer.visible and get_tree().paused) + click_room("hangar") + await capture("hangar") + var repair := button_starting("NAPRAW DO 100") + assert(repair != null and not repair.disabled) + repair.pressed.emit() + assert(GameState.captain.expedition.lander_hp == 100) + assert(GameState.captain.parts == 53) + # Full cargo must not lose the expedition's recovered module. + var inventory: ShipInventory = game.player.get_node("ShipInventory") + var module := preload("res://scripts/items/item_generator.gd").generate_for_definition(preload("res://resources/items/reinforced_shield.tres"),3) + for index in inventory.cargo.size(): inventory.cargo[index] = module + GameState.captain.expedition.delivered_modules.append(module) + screen._refresh() + button_starting("ODBIERZ").pressed.emit() + assert(GameState.captain.expedition.delivered_modules.size() == 1) + inventory.cargo[0] = null + button_starting("ODBIERZ").pressed.emit() + assert(GameState.captain.expedition.delivered_modules.is_empty()) + var credits_before: int = GameState.captain.credits + var parts_before: float = GameState.captain.parts + var minerals_before: Dictionary = GameState.captain.minerals.duplicate() + assert(screen.deck.room_nodes.size() == 8) + for id in ["expansion_1","expansion_2","expansion_3","cabin_1","cabin_2","cabin_3","cabin_4","cabin_5"]: + click_room(id) + assert(not screen.deck.is_built(id)) + var construct := button_starting("ZBUDUJ") + assert(construct != null) + construct.pressed.emit() + assert(screen.deck.is_built(id)) + assert(screen.deck.room_nodes[id].built) + assert(screen.deck.room(id).status == "ZBUDOWANO") + assert(button_starting("ZBUDUJ") == null) + screen._construct_room(id) # Repeated requests must be harmless. + assert(GameState.captain.expedition.freighter_rooms.size() == 8) + assert(GameState.captain.credits == credits_before) + assert(GameState.captain.parts == parts_before) + assert(GameState.captain.minerals == minerals_before) + # Room state is an exported resource field, ready for game save serialization. + assert(ResourceSaver.save(GameState.captain.expedition,"user://freighter_rooms_test.tres") == OK) + var restored: Resource = ResourceLoader.load("user://freighter_rooms_test.tres","",ResourceLoader.CACHE_MODE_IGNORE) + assert(restored.freighter_rooms == GameState.captain.expedition.freighter_rooms) + DirAccess.remove_absolute("user://freighter_rooms_test.tres") + screen._close_section() + await capture("built") + var leave := InputEventKey.new() + leave.pressed = true + leave.keycode = KEY_L + screen._input(leave) + assert(not get_tree().paused and not game.player.is_docked) + manager.open_freighter() + screen = manager.screen + assert(screen.deck.room_nodes.size() == 8) + for id in GameState.captain.expedition.freighter_rooms: + assert(screen.deck.is_built(id) and screen.deck.room_nodes[id].built) + screen.closed.emit() + game.queue_free() + await get_tree().process_frame + # The scene can also be opened directly in the editor without a live inventory. + GameState.selected_ship_path = "res://assets/Ships/player/zmija.png" + screen = preload("res://scenes/planets/freighter_interior.tscn").instantiate() + add_child(screen) + await capture("second_ship") + assert(screen.deck.ship_texture.resource_path == GameState.selected_ship_path) + screen.queue_free() + await get_tree().process_frame + print("FREIGHTER INTERIOR PASS: 8 free replaceable rooms, duplicate construction, resource serialization, redocking persistence, real ship, workshop, repair, cargo and ESC/L") + get_tree().quit() diff --git a/tests/previews/freighter_interior_preview.gd.uid b/tests/previews/freighter_interior_preview.gd.uid new file mode 100644 index 0000000..c6597b1 --- /dev/null +++ b/tests/previews/freighter_interior_preview.gd.uid @@ -0,0 +1 @@ +uid://d13sqcjymgupa diff --git a/tests/previews/freighter_interior_preview.tscn b/tests/previews/freighter_interior_preview.tscn new file mode 100644 index 0000000..264018a --- /dev/null +++ b/tests/previews/freighter_interior_preview.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/freighter_interior_preview.gd" id="1"] +[node name="FreighterInteriorPreview" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/planet_services_preview.gd b/tests/previews/planet_services_preview.gd index 7f4751c..d9f68d5 100644 --- a/tests/previews/planet_services_preview.gd +++ b/tests/previews/planet_services_preview.gd @@ -7,7 +7,7 @@ func _ready() -> void: player.get_node("WeaponController").set_physics_process(false) for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false) - player.position = protected_planet.position + Vector2(float(protected_planet.get("radius")) + 110.0, 0) + player.position = protected_planet.position + Vector2(float(protected_planet.get("radius")) * 0.75, 0) player.reset_physics_interpolation() GameState.captain.credits = 2500 GameState.captain.skills["business_shark"] = 2 @@ -19,6 +19,11 @@ func _ready() -> void: await get_tree().create_timer(0.5).timeout assert(services_menu.get("panel").size.x <= 340.0) assert(services_menu.get("panel").size.y <= 290.0) + var manager := get_node("PlanetExpeditions") + manager._process(0) + manager._layout_prompt() + if manager._prompt.visible: + assert(not services_menu.get_global_rect().intersects(manager._prompt.get_global_rect()),"Supply and telemetry cards must not overlap") if "--capture-preview" in OS.get_cmdline_user_args(): await RenderingServer.frame_post_draw get_viewport().get_texture().get_image().save_png("res://artifacts/planet_services_preview.png") diff --git a/tests/previews/planet_threats_preview.gd.uid b/tests/previews/planet_threats_preview.gd.uid new file mode 100644 index 0000000..a2d1fc5 --- /dev/null +++ b/tests/previews/planet_threats_preview.gd.uid @@ -0,0 +1 @@ +uid://bscpsspc0qr diff --git a/tests/previews/surface_atmosphere_test.gd b/tests/previews/surface_atmosphere_test.gd new file mode 100644 index 0000000..75f0109 --- /dev/null +++ b/tests/previews/surface_atmosphere_test.gd @@ -0,0 +1,101 @@ +extends Node +const RANGE := preload("res://scripts/planets/orbital_contact_range.gd") + +func settle() -> void: + for frame in 5: await get_tree().process_frame + await RenderingServer.frame_post_draw + +func capture(name: String) -> void: + await settle() + get_viewport().get_texture().get_image().save_png("res://artifacts/surface_atmosphere_%s.png" % name) + +func _ready() -> void: + GameState.start_new_run() + GameState.system_seed = 8428159 + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + var manager := game.get_node("PlanetExpeditions") + for enemy in get_tree().get_nodes_in_group("enemies"): enemy.position = Vector2(9999,9999) + game.player.landing_combat_lock = 0 + game.player.set_physics_process(false) + var planet: Node2D = game.protected_planet + game.player.position = planet.position+Vector2(planet.radius+40,0) + manager._message_time = 0 + manager._process(0) + assert(not manager._prompt.visible and not game.is_near_protected_planet()) + game.player.position = planet.position+Vector2(planet.radius*0.85,0) + manager._process(0) + assert(manager._prompt.visible and game.is_near_protected_planet()) + game.player.position = manager.freighter.position+Vector2(140,0) + manager._process(0) + assert(not RANGE.at_freighter(game.player,manager.freighter)) + game.player.position = manager.freighter.position+Vector2(45,0) + manager._process(0) + assert(manager._prompt.visible and manager._land_button.text == "DOKUJ [L]") + game.player.position = manager.freighter.position+Vector2(0,155) + assert(not RANGE.at_freighter(game.player,manager.freighter)) + game.free() + var progress: Resource = GameState.captain.expedition + var profile: Dictionary = preload("res://scripts/planets/planet_profiles.gd").generate(99,0,"Atmosfera") + profile.temperature = 20 + profile.oxygen = 98 + profile.flora = 0 + assert(progress.begin_visit(profile)) + progress.visit_seed = 200 + var surface := Control.new() + surface.set_script(preload("res://scripts/planets/surface_screen.gd")) + surface.captain = GameState.captain + surface.progress = progress + add_child(surface) + surface.set_physics_process(false) + surface.set_process(false) + var atmosphere: Node2D = surface._surface_viewport.get_node("SurfaceAtmosphere") + var mountains: Node2D = surface.world.get_node("Mountains") + assert(mountains.material.shader.resource_path.ends_with("mountain_blend.gdshader")) + assert(atmosphere.clouds.z_index > surface.lander.z_index) + assert(atmosphere.shadows.z_index < surface.lander.z_index) + assert(atmosphere._banks.size() == 49) + assert(atmosphere.TEXTURE.get_image().has_mipmaps()) + var target: Vector2 = surface.world.data.mountains[0].position + for mountain in surface.world.data.mountains: + if mountain.position.length_squared() < target.length_squared(): target = mountain.position + surface.lander.position = target+Vector2(70,50) + surface.lander.reset_physics_interpolation() + surface.camera.position_smoothing_enabled = false + surface.camera.position = target + surface.camera.force_update_scroll() + await settle() + # Freeze time and compare camera-space displacement: clouds must move faster. + atmosphere.set_process(false) + atmosphere._process(0) + var bank: Dictionary = atmosphere._banks[0] + var previous: Vector2 = bank.mist.position + var previous_center: Vector2 = surface.camera.get_screen_center_position() + surface.camera.position += Vector2(100,0) + surface.camera.force_update_scroll() + await settle() + atmosphere._process(0) + var center_delta: Vector2 = surface.camera.get_screen_center_position()-previous_center + assert(center_delta.length() > 50) + assert(bank.mist.position.is_equal_approx(previous+center_delta*(1.0-float(bank.parallax)))) + previous = bank.mist.position + atmosphere._process(1.0) + assert(bank.mist.position.distance_to(previous) > 4) + surface.camera.position = target + surface.camera.force_update_scroll() + atmosphere._process(0) + var blend: Material = mountains.material + mountains.material = null + atmosphere.hide() + await capture("before") + mountains.material = blend + await capture("mountains") + atmosphere.show() + atmosphere.set_process(true) + await capture("clouds") + progress.finish_visit(GameState.captain,false) + surface.queue_free() + await get_tree().process_frame + print("SURFACE ATMOSPHERE PASS: close-only planet/freighter contact, shared service range, transparent clouds above ship, shadows below, two parallax speeds, wind, mipmaps, blended mountains") + get_tree().quit() diff --git a/tests/previews/surface_atmosphere_test.gd.uid b/tests/previews/surface_atmosphere_test.gd.uid new file mode 100644 index 0000000..aa1ab05 --- /dev/null +++ b/tests/previews/surface_atmosphere_test.gd.uid @@ -0,0 +1 @@ +uid://badnwt7ddtajf diff --git a/tests/previews/surface_atmosphere_test.tscn b/tests/previews/surface_atmosphere_test.tscn new file mode 100644 index 0000000..3b98157 --- /dev/null +++ b/tests/previews/surface_atmosphere_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/previews/surface_atmosphere_test.gd" id="1"] +[node name="SurfaceAtmosphereTest" type="Node"] +script = ExtResource("1") diff --git a/tests/previews/surface_details_test.gd b/tests/previews/surface_details_test.gd index e38dd7e..c7e67ea 100644 --- a/tests/previews/surface_details_test.gd +++ b/tests/previews/surface_details_test.gd @@ -9,7 +9,7 @@ func _initialize() -> void: var profile := {"temperature":75 if biome == 4 else (-35 if biome == 5 else 20)} var data := GENERATOR.generate(200+biome, profile) assert(int(data.landscape.index) == biome) - assert(data.pois.size() == 8 and data.structures.size() <= 5) + assert(data.pois.size() >= 4 and data.pois.size() <= 6 and data.structures.size() <= 5) var original := var_to_str(data.details) DETAILS.generate(data) assert(original == var_to_str(data.details), "Decoration generation must be reproducible") diff --git a/tests/previews/surface_events_preview.gd.uid b/tests/previews/surface_events_preview.gd.uid new file mode 100644 index 0000000..3916b60 --- /dev/null +++ b/tests/previews/surface_events_preview.gd.uid @@ -0,0 +1 @@ +uid://bl31a23swrf0t diff --git a/tests/ships/freighter_storage_test.gd b/tests/ships/freighter_storage_test.gd new file mode 100644 index 0000000..359e574 --- /dev/null +++ b/tests/ships/freighter_storage_test.gd @@ -0,0 +1,89 @@ +extends Node +var screen: Control + +func settle() -> void: + for frame in 5: await get_tree().process_frame + +func find_button(prefix: String) -> Button: + for node in screen._content.find_children("*","Button",true,false): + if node.text.begins_with(prefix): return node + return null + +func _ready() -> void: + GameState.start_new_run() + GameState.selected_ship_path = "res://assets/Ships/player/bastion.png" + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + 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) + 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)) + assert(not inv.store_on_freighter(0,items[0],captain)) + var manager := game.get_node("PlanetExpeditions") + manager.open_freighter() + screen = manager.screen + screen._select_section("storage") + assert(find_button("ZBUDUJ SKŁAD") != null) + assert(not inv.store_on_freighter(0,items[0],captain)) + find_button("ZBUDUJ SKŁAD").pressed.emit() + assert(find_button("ODŁÓŻ") != null) + find_button("ODŁÓŻ").pressed.emit() + assert(captain.expedition.freighter_storage[0] == items[0]) + assert(inv.cargo[0] == null) + assert(not inv.store_on_freighter(0,items[0],captain)) + assert(inv.add_item(items[5])) + assert(not inv.retrieve_from_freighter(0,items[0],captain)) + assert(captain.expedition.freighter_storage.size() == 1) + screen._refresh() + 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 + screen._refresh() + find_button("ODBLOKUJ RZĄD").pressed.emit() + assert(inv.get_cargo_capacity() == 10 and captain.minerals.iron == 20) + screen._select_section("storage") + find_button("← ODBIERZ").pressed.emit() + assert(inv.cargo[5] == items[0] and captain.expedition.freighter_storage.is_empty()) + assert(inv.store_on_freighter(1,items[1],captain)) + assert(inv.store_on_freighter(2,items[2],captain)) + assert(not inv.retrieve_from_freighter(0,items[2],captain),"Stale buttons cannot transfer another item") + screen._refresh() + 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)) + 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(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) + assert(restored.freighter_storage[0].item_level == items[1].item_level) + DirAccess.remove_absolute("user://freighter_storage_test.tres") + inv.preserve_for_restart() + screen.closed.emit() + assert(not inv.retrieve_from_freighter(0,items[1],captain)) + 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() == 20 and captain.expedition.freighter_storage.size() == 2) + game.get_node("PlanetExpeditions").open_freighter() + assert(inv.retrieve_from_freighter(0,items[1],captain)) + game.get_node("PlanetExpeditions").screen.closed.emit() + 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") + get_tree().quit() diff --git a/tests/ships/freighter_storage_test.gd.uid b/tests/ships/freighter_storage_test.gd.uid new file mode 100644 index 0000000..1e469b7 --- /dev/null +++ b/tests/ships/freighter_storage_test.gd.uid @@ -0,0 +1 @@ +uid://cmef23uysc5tw diff --git a/tests/ships/freighter_storage_test.tscn b/tests/ships/freighter_storage_test.tscn new file mode 100644 index 0000000..b3789a5 --- /dev/null +++ b/tests/ships/freighter_storage_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/ships/freighter_storage_test.gd" id="1"] +[node name="FreighterStorageTest" type="Node"] +script = ExtResource("1") diff --git a/tests/ships/slot_unlock_test.gd b/tests/ships/slot_unlock_test.gd new file mode 100644 index 0000000..d8dcb83 --- /dev/null +++ b/tests/ships/slot_unlock_test.gd @@ -0,0 +1,70 @@ +extends Node + +func settle() -> void: + for frame in 5: await get_tree().process_frame + +func _ready() -> void: + GameState.start_new_run() + GameState.selected_ship_path = "res://assets/Ships/player/bastion.png" + var game := preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + var inv: ShipInventory = game.player.get_node("ShipInventory") + var captain := GameState.captain + assert(inv.unlocked_weapon_slots == 1 and inv.unlocked_extension_slots == 1) + assert(inv.is_slot_unlocked("weapon",0) and not inv.is_slot_unlocked("weapon",1)) + var weapon: ItemInstance = inv.weapon_slots[0] + inv.cargo[0] = weapon + assert(not inv.can_move_item("cargo",0,"weapon",1)) + var extension: ItemInstance = preload("res://scripts/items/item_generator.gd").generate_for_definition(preload("res://resources/items/teleport.tres"),1) + 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["iron"] = 100 + assert(not inv.unlock_slot("weapon",captain),"Unlock requires docking") + assert(captain.minerals.iron == 100) + var manager := game.get_node("PlanetExpeditions") + manager.open_freighter() + var screen: Control = manager.screen + screen._select_section("hangar") + captain.minerals["iron"] = 9 + screen._refresh() + assert(not inv.unlock_slot("weapon",captain)) + assert(captain.minerals.iron == 9 and inv.unlocked_weapon_slots == 1) + captain.minerals["iron"] = 60 + screen._refresh() + await settle() + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png("res://artifacts/hangar_slot_unlock.png") + var button: Button + for node in screen._content.find_children("*","Button",true,false): + if node.text.begins_with("ODBLOKUJ SLOT BRONI"): 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.can_move_item("cargo",0,"weapon",1)) + assert(inv.unlock_slot("weapon",captain)) + for index in 4: assert(inv.unlock_slot("extension",captain)) + assert(inv.unlocked_weapon_slots == 3 and inv.unlocked_extension_slots == 5) + assert(captain.minerals.iron == 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) + inv.preserve_for_restart() + screen.closed.emit() + game.free() + game = preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + inv = game.player.get_node("ShipInventory") + assert(inv.unlocked_weapon_slots == 3 and inv.unlocked_extension_slots == 5) + game.free() + GameState.start_new_run() + game = preload("res://scenes/game/game.tscn").instantiate() + add_child(game) + await settle() + 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") + get_tree().quit() diff --git a/tests/ships/slot_unlock_test.gd.uid b/tests/ships/slot_unlock_test.gd.uid new file mode 100644 index 0000000..1c8bc2a --- /dev/null +++ b/tests/ships/slot_unlock_test.gd.uid @@ -0,0 +1 @@ +uid://das3qt0o8nrnu diff --git a/tests/ships/slot_unlock_test.tscn b/tests/ships/slot_unlock_test.tscn new file mode 100644 index 0000000..19d63d8 --- /dev/null +++ b/tests/ships/slot_unlock_test.tscn @@ -0,0 +1,4 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://tests/ships/slot_unlock_test.gd" id="1"] +[node name="SlotUnlockTest" type="Node"] +script = ExtResource("1")