This commit is contained in:
Tomasz Boruc 2026-10-13 21:50:09 +02:00
parent f12ed2f67e
commit 9808a03d13
44 changed files with 885 additions and 91 deletions

BIN
assets/icons/gamma.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bgs1htiuvgmic"
path="res://.godot/imported/gamma.png-96d3080e05fe2aad0fc3e1de127f7d0d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/gamma.png"
dest_files=["res://.godot/imported/gamma.png-96d3080e05fe2aad0fc3e1de127f7d0d.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

View File

@ -0,0 +1,10 @@
# Działko gamma
Generated with the built-in image_gen tool.
Style reference: `assets/icons/plasma.png`.
Output: `assets/icons/gamma.png`, transparent background.
## Prompt
Create a production-quality square game inventory icon for a spaceship GAMMA CANNON, matching the supplied plasma-cannon reference's detailed metallic 3D science-fiction rendering, three-quarter isometric view and crisp strong silhouette. Reference image is for style and perspective only. Design a DIFFERENT distinct weapon: compact heavy orbital gamma emitter with layered gunmetal and brushed silver shielding plates, dark mechanical rear mount, a broad circular emitter muzzle facing lower right, a bright lime-green irradiated spherical core contained between three radial containment prongs, a few small orbiting green particles within the muzzle, luminous green coolant conduits and small restrained brass accents. Industrial believable spaceship-mounted turret, no pistol handle. Radiation aesthetic in green, no purple plasma. The cannon alone occupies 85 percent of the square, centered, all parts fully in frame, no cropped extremities. Readable at 48px thumbnail, bold broad shapes and controlled highlights, no background scene, no border, no labels, no lettering, no text. Genuine transparent background and clean alpha edges, no ground or drop shadow. Single isolated icon.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ooii0cnkunnb"
path="res://.godot/imported/aluminium.png-63588dbb597f01d62b3f0366767573a6.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/aluminium.png"
dest_files=["res://.godot/imported/aluminium.png-63588dbb597f01d62b3f0366767573a6.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bvxxyh35g4qgh"
path="res://.godot/imported/ammunition.png-55b812a61f21303b828ce907b57955d0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/ammunition.png"
dest_files=["res://.godot/imported/ammunition.png-55b812a61f21303b828ce907b57955d0.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bt0ve4g2lbcxc"
path="res://.godot/imported/iron.png-9f0bab611f228be580c28e352ca1d8cc.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/iron.png"
dest_files=["res://.godot/imported/iron.png-9f0bab611f228be580c28e352ca1d8cc.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwg8xyrhjg2ql"
path="res://.godot/imported/irradiated_ammunition.png-43f90162db35d57c3d57de6de22435e4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/irradiated_ammunition.png"
dest_files=["res://.godot/imported/irradiated_ammunition.png-43f90162db35d57c3d57de6de22435e4.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ns3mapyv4n2g"
path="res://.godot/imported/missile.png-d91a6d6e7348b7fba50d4cc3ac087245.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/missile.png"
dest_files=["res://.godot/imported/missile.png-d91a6d6e7348b7fba50d4cc3ac087245.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b1gltl1goxq3a"
path="res://.godot/imported/parts.png-f14343f401c851f9b669606251dc7106.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/parts.png"
dest_files=["res://.godot/imported/parts.png-f14343f401c851f9b669606251dc7106.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

View File

@ -0,0 +1,46 @@
{
"tool": "built-in image_gen",
"transparent_background": true,
"prompts": [
{
"key": "iron",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a rugged dark graphite-gray iron ore nugget with a few rusty orange seams and raw crystalline metallic facets, clearly a mined mineral",
"asset": "assets/icons/resources/iron.png"
},
{
"key": "titanium",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a chunky cool blue-gray titanium ore crystal with silver-blue metallic facets and pale blue edge highlights, clearly different from iron",
"asset": "assets/icons/resources/titanium.png"
},
{
"key": "aluminium",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: two small stacked refined aluminium ingots, bright matte silvery metal, pale cool white reflections, clean beveled edges",
"asset": "assets/icons/resources/aluminium.png"
},
{
"key": "uranium",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a rugged uranium ore chunk, dark stone with luminous toxic lime-green mineral veins and tiny green crystal inclusions, unmistakable radiation resource",
"asset": "assets/icons/resources/uranium.png"
},
{
"key": "parts",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a compact cluster of mechanical salvage parts: one steel gear, one brass bearing and a small bent circuit board, bold readable silhouette",
"asset": "assets/icons/resources/parts.png"
},
{
"key": "ammunition",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: three short brass-cased autocannon cartridges with metallic copper tips, grouped neatly, one cartridge slightly taller",
"asset": "assets/icons/resources/ammunition.png"
},
{
"key": "irradiated_ammunition",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: two futuristic gamma cannon ammunition capsules: armored dark steel cylindrical casings, small containment bands and luminous lime-green sealed cores, no conventional bullets",
"asset": "assets/icons/resources/irradiated_ammunition.png"
},
{
"key": "missile",
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a single compact spaceship missile with pointed silver nose, dark steel casing, two small red fins and a restrained orange rear nozzle, diagonal three-quarter view",
"asset": "assets/icons/resources/missile.png"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://e3hyjgddtws3"
path="res://.godot/imported/titanium.png-0b4998bc95056c5a7906568e449b30ff.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/titanium.png"
dest_files=["res://.godot/imported/titanium.png-0b4998bc95056c5a7906568e449b30ff.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b6enhdjvecuep"
path="res://.godot/imported/uranium.png-ceac43be56616b10258ea19f379a1280.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/resources/uranium.png"
dest_files=["res://.godot/imported/uranium.png-ceac43be56616b10258ea19f379a1280.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

View File

@ -1,6 +1,6 @@
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3] [gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1"] [ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1"]
[ext_resource type="Texture2D" path="res://assets/icons/gamma.svg" id="icon"] [ext_resource type="Texture2D" path="res://assets/icons/gamma.png" id="icon"]
[resource] [resource]
script = ExtResource("1") script = ExtResource("1")
icon = ExtResource("icon") icon = ExtResource("icon")

View File

@ -1,6 +1,16 @@
[gd_resource type="Theme" load_steps=2 format=3] [gd_resource type="Theme" load_steps=3 format=3]
[ext_resource type="FontFile" path="res://assets/fonts/font2.ttf" id="1_font"] [ext_resource type="FontFile" path="res://assets/fonts/font2.ttf" id="1_font"]
[sub_resource type="StyleBoxFlat" id="TooltipShell"]
bg_color = Color(0.035, 0.055, 0.085, 1)
content_margin_left = 2.0
content_margin_top = 2.0
content_margin_right = 2.0
content_margin_bottom = 2.0
shadow_size = 0
[resource] [resource]
default_font = ExtResource("1_font") default_font = ExtResource("1_font")
TooltipPanel/styles/panel = SubResource("TooltipShell")
TooltipLabel/font_sizes/font_size = 11

View File

@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"] [ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"]
[sub_resource type="StyleBoxFlat" id="PanelStyle"] [sub_resource type="StyleBoxFlat" id="PanelStyle"]
bg_color = Color(0.045, 0.075, 0.11, 1) bg_color = Color(0.045, 0.075, 0.11, 0.64)
border_width_left = 1 border_width_left = 1
border_width_top = 1 border_width_top = 1
border_width_right = 1 border_width_right = 1

View File

@ -43,7 +43,7 @@ text = "SYSTEMY POKŁADOWE"
horizontal_alignment = 1 horizontal_alignment = 1
[node name="EquipmentLayout" type="Control" parent="Contents"] [node name="EquipmentLayout" type="Control" parent="Contents"]
custom_minimum_size = Vector2(284, 456) custom_minimum_size = Vector2(284, 552)
layout_mode = 2 layout_mode = 2
mouse_filter = 2 mouse_filter = 2
@ -100,9 +100,9 @@ overlay_slot = true
[node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 14.0 offset_left = 14.0
offset_top = 178.0 offset_top = 200.0
offset_right = 78.0 offset_right = 78.0
offset_bottom = 242.0 offset_bottom = 264.0
slot_kind = "module" slot_kind = "module"
slot_index = 1 slot_index = 1
overlay_slot = true overlay_slot = true
@ -110,9 +110,9 @@ overlay_slot = true
[node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 14.0 offset_left = 14.0
offset_top = 248.0 offset_top = 292.0
offset_right = 78.0 offset_right = 78.0
offset_bottom = 312.0 offset_bottom = 356.0
slot_kind = "module" slot_kind = "module"
slot_index = 2 slot_index = 2
overlay_slot = true overlay_slot = true
@ -120,9 +120,9 @@ overlay_slot = true
[node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 14.0 offset_left = 14.0
offset_top = 318.0 offset_top = 384.0
offset_right = 78.0 offset_right = 78.0
offset_bottom = 382.0 offset_bottom = 448.0
slot_kind = "module" slot_kind = "module"
slot_index = 3 slot_index = 3
overlay_slot = true overlay_slot = true
@ -130,9 +130,9 @@ overlay_slot = true
[node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 14.0 offset_left = 14.0
offset_top = 388.0 offset_top = 476.0
offset_right = 78.0 offset_right = 78.0
offset_bottom = 452.0 offset_bottom = 540.0
slot_kind = "module" slot_kind = "module"
slot_index = 4 slot_index = 4
overlay_slot = true overlay_slot = true
@ -150,9 +150,9 @@ overlay_slot = true
[node name="Extension2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Extension2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 206.0 offset_left = 206.0
offset_top = 178.0 offset_top = 200.0
offset_right = 270.0 offset_right = 270.0
offset_bottom = 242.0 offset_bottom = 264.0
slot_kind = "extension" slot_kind = "extension"
slot_index = 1 slot_index = 1
overlay_slot = true overlay_slot = true
@ -160,9 +160,9 @@ overlay_slot = true
[node name="Extension3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Extension3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 206.0 offset_left = 206.0
offset_top = 248.0 offset_top = 292.0
offset_right = 270.0 offset_right = 270.0
offset_bottom = 312.0 offset_bottom = 356.0
slot_kind = "extension" slot_kind = "extension"
slot_index = 2 slot_index = 2
overlay_slot = true overlay_slot = true
@ -170,9 +170,9 @@ overlay_slot = true
[node name="Extension4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Extension4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 206.0 offset_left = 206.0
offset_top = 318.0 offset_top = 384.0
offset_right = 270.0 offset_right = 270.0
offset_bottom = 382.0 offset_bottom = 448.0
slot_kind = "extension" slot_kind = "extension"
slot_index = 3 slot_index = 3
overlay_slot = true overlay_slot = true
@ -180,9 +180,9 @@ overlay_slot = true
[node name="Extension5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] [node name="Extension5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
layout_mode = 0 layout_mode = 0
offset_left = 206.0 offset_left = 206.0
offset_top = 388.0 offset_top = 476.0
offset_right = 270.0 offset_right = 270.0
offset_bottom = 452.0 offset_bottom = 540.0
slot_kind = "extension" slot_kind = "extension"
slot_index = 4 slot_index = 4
overlay_slot = true overlay_slot = true

View File

@ -49,16 +49,6 @@ layout_mode = 2
theme_override_font_sizes/font_size = 11 theme_override_font_sizes/font_size = 11
text = "ZAMKNIJ" text = "ZAMKNIJ"
[node name="Ammunition" type="HBoxContainer" parent="Contents"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Count" type="Label" parent="Contents/Ammunition"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 11
text = "AMUNICJA: 50"
[node name="CargoGrid" type="GridContainer" parent="Contents"] [node name="CargoGrid" type="GridContainer" parent="Contents"]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 4 size_flags_horizontal = 4

View File

@ -7,6 +7,9 @@ const ITEM_GENERATOR := preload("res://scripts/items/item_generator.gd")
const LOOT_PICKUP := preload("res://scripts/items/loot_pickup.gd") const LOOT_PICKUP := preload("res://scripts/items/loot_pickup.gd")
const LOOT_OFFSET := Vector2(0, 36) const LOOT_OFFSET := Vector2(0, 36)
const LEVEL_BALANCE := preload("res://scripts/levels/level_balance.gd") const LEVEL_BALANCE := preload("res://scripts/levels/level_balance.gd")
const LASER_COOLDOWN_MULTIPLIER := 2.0
const LASER_MINIMUM_COOLDOWN := 1.4
const LASER_MISS_CHANCE := 0.35
@export_enum("Normal", "Elite", "Boss") var loot_tier: int = 0 @export_enum("Normal", "Elite", "Boss") var loot_tier: int = 0
@ -40,7 +43,7 @@ func _ready() -> void:
add_child(_shield_visual) add_child(_shield_visual)
_shield_visual.set_shield_values(shields, max_shields) _shield_visual.set_shield_values(shields, max_shields)
add_to_group("enemies") add_to_group("enemies")
_weapon_timer = randf_range(0.2, weapon_cooldown) _weapon_timer = randf_range(0.2, get_fire_interval())
func apply_level_settings(level: int, tier: int) -> void: func apply_level_settings(level: int, tier: int) -> void:
loot_tier = tier loot_tier = tier
@ -102,7 +105,7 @@ func _physics_process(delta: float) -> void:
_weapon_timer = maxf(0.0, _weapon_timer - delta) _weapon_timer = maxf(0.0, _weapon_timer - delta)
if to_player.length() <= weapon_range and _weapon_timer <= 0.0: if to_player.length() <= weapon_range and _weapon_timer <= 0.0:
_fire_plasma(direction) _fire_plasma(direction)
_weapon_timer = weapon_cooldown _weapon_timer = get_fire_interval()
else: else:
velocity = velocity.move_toward(Vector2.ZERO, approach_acceleration * delta) velocity = velocity.move_toward(Vector2.ZERO, approach_acceleration * delta)
@ -118,7 +121,7 @@ func _check_player_collision() -> void:
func _fire_plasma(direction: Vector2) -> void: func _fire_plasma(direction: Vector2) -> void:
var muzzle := global_position + direction * (get_visual_size() * 0.5 + 8.0) var muzzle := global_position + direction * (get_visual_size() * 0.5 + 8.0)
if weapon_kind == ItemDefinition.WeaponKind.LASER: if weapon_kind == ItemDefinition.WeaponKind.LASER:
var endpoint := muzzle + direction * weapon_range var endpoint := muzzle + _laser_aim_direction(direction) * weapon_range
var query := PhysicsRayQueryParameters2D.create(muzzle, endpoint, 3, [get_rid()]) var query := PhysicsRayQueryParameters2D.create(muzzle, endpoint, 3, [get_rid()])
var hit := get_world_2d().direct_space_state.intersect_ray(query) var hit := get_world_2d().direct_space_state.intersect_ray(query)
if not hit.is_empty(): if not hit.is_empty():
@ -170,8 +173,22 @@ func take_damage(amount: float, critical: bool = false, damage_type: int = Damag
_spawn_destruction_effect() _spawn_destruction_effect()
queue_free() queue_free()
func get_fire_interval() -> float:
if weapon_kind == ItemDefinition.WeaponKind.LASER:
return maxf(LASER_MINIMUM_COOLDOWN, weapon_cooldown * LASER_COOLDOWN_MULTIPLIER)
return weapon_cooldown
func _laser_aim_direction(direction: Vector2) -> Vector2:
if randf() < LASER_MISS_CHANCE:
var side := Vector2(-direction.y, direction.x)
var distance := global_position.distance_to(_player.global_position) if is_instance_valid(_player) else weapon_range
var offset := randf_range(60.0, 110.0) * (-1.0 if randf() < 0.5 else 1.0)
return (direction * maxf(1.0, distance) + side * offset).normalized()
return direction.rotated(randf_range(-0.02, 0.02))
func get_weapon_dps() -> float: func get_weapon_dps() -> float:
return weapon_damage / maxf(0.001, weapon_cooldown) * (1.0 + 0.25 * minf(3.0, weapon_cooldown) if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0) var interval := get_fire_interval()
return weapon_damage / maxf(0.001, interval) * (1.0 + 0.25 * minf(3.0, interval) if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0)
func _reward_captain() -> void: func _reward_captain() -> void:
if is_instance_valid(_player): if is_instance_valid(_player):

View File

@ -19,6 +19,9 @@ var _sidebar_tween: Tween
const SIDEBAR_WIDTH := 306.0 const SIDEBAR_WIDTH := 306.0
const EQUIPMENT_UI_SCALE := 0.8 const EQUIPMENT_UI_SCALE := 0.8
var _debug_scroll: ScrollContainer var _debug_scroll: ScrollContainer
var _debug_actions: VBoxContainer
var _debug_item_button: Button
var _debug_item_status: Label
var _captain_panel: PanelContainer var _captain_panel: PanelContainer
var _cockpit: Control var _cockpit: Control
@ -70,6 +73,23 @@ func _create_sidebar() -> void:
_captain_panel.position = Vector2(12, 12) _captain_panel.position = Vector2(12, 12)
_captain_panel.size = Vector2(320, _captain_panel.get_combined_minimum_size().y) _captain_panel.size = Vector2(320, _captain_panel.get_combined_minimum_size().y)
_captain_panel.resized.connect(_layout_debug) _captain_panel.resized.connect(_layout_debug)
_debug_actions = VBoxContainer.new()
_debug_actions.name = "DebugActions"
_debug_actions.add_theme_constant_override("separation", 6)
$HUDRoot.add_child(_debug_actions)
_debug_item_button = Button.new()
_debug_item_button.name = "GenerateItem"
_debug_item_button.custom_minimum_size.y = 36
preload("res://scripts/ui/hud_button_style.gd").apply(_debug_item_button, Color("a9ef83"))
_debug_item_button.pressed.connect(_give_debug_item)
_debug_actions.add_child(_debug_item_button)
_debug_item_status = Label.new()
_debug_item_status.add_theme_font_size_override("font_size", 10)
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
_debug_item_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_debug_item_status.hide()
_debug_actions.add_child(_debug_item_status)
_debug_actions.minimum_size_changed.connect(func() -> void: _layout_debug.call_deferred())
_debug_scroll = ScrollContainer.new() _debug_scroll = ScrollContainer.new()
_debug_scroll.name = "DebugScroll" _debug_scroll.name = "DebugScroll"
_debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED _debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
@ -110,13 +130,14 @@ func _create_sidebar() -> void:
_sidebar_toggle.name = "ShipToggle" _sidebar_toggle.name = "ShipToggle"
_sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀" _sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
_sidebar_toggle.add_theme_font_size_override("font_size", 12) _sidebar_toggle.add_theme_font_size_override("font_size", 12)
_sidebar_toggle.focus_mode = Control.FOCUS_NONE preload("res://scripts/ui/hud_button_style.gd").apply(_sidebar_toggle)
preload("res://scripts/ui/hud_button_style.gd").apply(inventory_button, Color("b9a0ef"))
$HUDRoot.add_child(_sidebar_toggle) $HUDRoot.add_child(_sidebar_toggle)
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT) _sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
_sidebar_toggle.offset_left = -180 _sidebar_toggle.offset_left = -180
_sidebar_toggle.offset_right = -12 _sidebar_toggle.offset_right = -12
_sidebar_toggle.offset_top = 12 _sidebar_toggle.offset_top = 12
_sidebar_toggle.offset_bottom = 40 _sidebar_toggle.offset_bottom = 48
_sidebar_toggle.pressed.connect(_toggle_sidebar) _sidebar_toggle.pressed.connect(_toggle_sidebar)
_cockpit = Control.new() _cockpit = Control.new()
_cockpit.name = "Cockpit" _cockpit.name = "Cockpit"
@ -131,8 +152,12 @@ func _layout_debug() -> void:
return return
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0 var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
debug_toggle.position = Vector2(12, top) debug_toggle.position = Vector2(12, top)
_debug_scroll.position = Vector2(18, top + 30) _debug_actions.position = Vector2(18, top + 30)
_debug_scroll.size = Vector2(310, maxf(40, $HUDRoot.size.y - top - 42)) _debug_actions.size = Vector2(310, _debug_actions.get_combined_minimum_size().y)
_debug_actions.visible = _debug_expanded
var scroll_top := _debug_actions.position.y + _debug_actions.size.y + 8.0
_debug_scroll.position = Vector2(18, scroll_top)
_debug_scroll.size = Vector2(310, maxf(40, $HUDRoot.size.y - scroll_top - 12))
_debug_scroll.visible = _debug_expanded _debug_scroll.visible = _debug_expanded
func _toggle_sidebar() -> void: func _toggle_sidebar() -> void:
@ -158,10 +183,14 @@ func _layout_sidebar() -> void:
_sidebar.scale = Vector2.ONE * EQUIPMENT_UI_SCALE _sidebar.scale = Vector2.ONE * EQUIPMENT_UI_SCALE
_sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), minf(_sidebar.get_node("Scroll/Contents").get_combined_minimum_size().y + 16.0, maxf(100.0, ($HUDRoot.size.y - 64.0) / EQUIPMENT_UI_SCALE))) _sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), minf(_sidebar.get_node("Scroll/Contents").get_combined_minimum_size().y + 16.0, maxf(100.0, ($HUDRoot.size.y - 64.0) / EQUIPMENT_UI_SCALE)))
_cockpit.scale = Vector2.ONE * 0.85 _cockpit.scale = Vector2.ONE * 0.85
_cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 170) _cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 104)
_cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12) _cockpit.position = Vector2(($HUDRoot.size.x - _cockpit.size.x * 0.85) * 0.5, $HUDRoot.size.y - _cockpit.size.y * 0.85 - 12)
if _ability_bar != null:
var abilities := _ability_bar.get_parent() as Control
abilities.offset_bottom = _cockpit.position.y - $HUDRoot.size.y - 14.0
abilities.offset_top = abilities.offset_bottom - 44.0
_layout_debug() _layout_debug()
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x * EQUIPMENT_UI_SCALE - 8 if _sidebar_open else $HUDRoot.size.x, 44) _sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x * EQUIPMENT_UI_SCALE - 8 if _sidebar_open else $HUDRoot.size.x, 56)
_sidebar.visible = _sidebar_open _sidebar.visible = _sidebar_open
_inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE _inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE
_layout_inventory() _layout_inventory()
@ -177,6 +206,10 @@ func _process(_delta: float) -> void:
_update_ability_bar() _update_ability_bar()
if not _debug_expanded: if not _debug_expanded:
return 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.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() var game := get_parent()
debug_info.text = """POZIOM UKŁADU: %d debug_info.text = """POZIOM UKŁADU: %d
WROGOWIE: %d WROGOWIE: %d
@ -200,7 +233,25 @@ func _toggle_debug() -> void:
GameState.hud_panel_state["debug_expanded"] = _debug_expanded GameState.hud_panel_state["debug_expanded"] = _debug_expanded
debug_info.visible = _debug_expanded debug_info.visible = _debug_expanded
_debug_scroll.visible = _debug_expanded _debug_scroll.visible = _debug_expanded
_debug_actions.visible = _debug_expanded
_update_debug_toggle() _update_debug_toggle()
_layout_debug()
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:
_debug_item_status.text = "Magazyn pełny — zwolnij miejsce."
_debug_item_status.add_theme_color_override("font_color", Color("ff8989"))
_layout_debug.call_deferred()
return false
var item := preload("res://scripts/items/item_generator.gd").generate(GameState.system_level)
if not inventory.add_item(item):
return false
_debug_item_status.text = "Dodano: %s · Poz. %d" % [item.definition.display_name, item.item_level]
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
_layout_debug.call_deferred()
return true
func _update_debug_toggle() -> void: func _update_debug_toggle() -> void:
debug_toggle.text = "DEBUG [−]" if _debug_expanded else "DEBUG [+]" debug_toggle.text = "DEBUG [−]" if _debug_expanded else "DEBUG [+]"
@ -261,8 +312,8 @@ func _create_ability_bar() -> void:
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM) panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
panel.offset_left = -120.0 panel.offset_left = -120.0
panel.offset_right = 120.0 panel.offset_right = 120.0
panel.offset_top = -176.0 panel.offset_top = -220.0
panel.offset_bottom = -132.0 panel.offset_bottom = -176.0
panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new()) panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
_ability_bar = HBoxContainer.new() _ability_bar = HBoxContainer.new()
_ability_bar.name = "AbilityButtons" _ability_bar.name = "AbilityButtons"

View File

@ -10,7 +10,7 @@ const WORLD_SIZE := SYSTEM_GENERATOR.WORLD_SIZE
const SERVICE_APPROACH_DISTANCE := 180.0 const SERVICE_APPROACH_DISTANCE := 180.0
const WORMHOLE_PLANET_DISTANCE := 620.0 const WORMHOLE_PLANET_DISTANCE := 620.0
const WORMHOLE_ENTRY_RADIUS := 48.0 const WORMHOLE_ENTRY_RADIUS := 48.0
const BOSS_SPAWN_DISTANCE := 900.0 const BOSS_SPAWN_DISTANCE := 1800.0
const BOSS_SPAWN_MARGIN := 160.0 const BOSS_SPAWN_MARGIN := 160.0
const ENEMY_SCENE := preload("res://scenes/game/enemy_ship.tscn") const ENEMY_SCENE := preload("res://scenes/game/enemy_ship.tscn")
const ENEMY_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES const ENEMY_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES

View File

@ -88,7 +88,8 @@ func get_addon_count() -> int:
return count return count
func get_background_color() -> Color: func get_background_color() -> Color:
return [Color("101925"), Color("414b58"), Color("65432d"), Color("244c79"), Color("796025")][mini(get_addon_count(), 4)] # No addons and one addon are black; the strongest tier is burgundy.
return [Color("080b10"), Color("080b10"), Color("603e28"), Color("285b91"), Color("8050b8"), Color("70243c")][clampi(get_addon_count(), 0, 5)]
func get_type_color() -> Color: func get_type_color() -> Color:
if definition == null: if definition == null:

View File

@ -22,7 +22,7 @@ func _ready() -> void:
_panel.add_child(_label) _panel.add_child(_label)
_toggle = Button.new() _toggle = Button.new()
_toggle.text = "WRÓG ▾" _toggle.text = "WRÓG ▾"
_toggle.focus_mode = Control.FOCUS_NONE preload("res://scripts/ui/hud_button_style.gd").apply(_toggle, Color("ff9aae"))
add_child(_toggle) add_child(_toggle)
_toggle.pressed.connect(_toggle_drawer) _toggle.pressed.connect(_toggle_drawer)
_open = bool(GameState.hud_panel_state.get("enemy_open", false)) _open = bool(GameState.hud_panel_state.get("enemy_open", false))
@ -32,9 +32,9 @@ func _ready() -> void:
func _layout() -> void: func _layout() -> void:
position.x = (get_viewport_rect().size.x - 390.0) * 0.5 position.x = (get_viewport_rect().size.x - 390.0) * 0.5
_panel.size = Vector2(390, 150) _panel.size = Vector2(390, 150)
_panel.position.y = 42.0 if _open else -160.0 _panel.position.y = 56.0 if _open else -160.0
_toggle.position = Vector2(130, 12) _toggle.position = Vector2(130, 12)
_toggle.size = Vector2(130, 28) _toggle.size = Vector2(130, 36)
func _toggle_drawer() -> void: func _toggle_drawer() -> void:
_open = not _open _open = not _open
@ -43,7 +43,7 @@ func _toggle_drawer() -> void:
if _tween != null: if _tween != null:
_tween.kill() _tween.kill()
_tween = create_tween() _tween = create_tween()
_tween.tween_property(_panel, "position:y", 42.0 if _open else -160.0, 0.25).set_trans(Tween.TRANS_CUBIC) _tween.tween_property(_panel, "position:y", 56.0 if _open else -160.0, 0.25).set_trans(Tween.TRANS_CUBIC)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
var enemy: Node = null var enemy: Node = null

View File

@ -59,7 +59,7 @@ func _ready() -> void:
var binding := Label.new() var binding := Label.new()
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
binding.text = (["LPM", "PPM", "ŚPM"][slot_index]) if slot_kind == "weapon" else (str(slot_index + 1) if slot_kind == "extension" else ShipInventory.MODULE_NAMES[slot_index]) binding.text = (["LPM", "PPM", "ŚPM"][slot_index]) if slot_kind == "weapon" else (str(slot_index + 1) if slot_kind == "extension" else ShipInventory.MODULE_NAMES[slot_index])
binding.position = Vector2(2, -14) binding.position = Vector2(2, -24)
binding.add_theme_font_size_override("font_size", 9) binding.add_theme_font_size_override("font_size", 9)
binding.add_theme_color_override("font_color", Color("a0b2c4")) binding.add_theme_color_override("font_color", Color("a0b2c4"))
# Use a plain overlay to keep the binding outside the slot's content layout. # Use a plain overlay to keep the binding outside the slot's content layout.
@ -134,42 +134,108 @@ func _delete_item() -> void:
func _make_custom_tooltip(for_text: String) -> Object: func _make_custom_tooltip(for_text: String) -> Object:
var panel := PanelContainer.new() var panel := PanelContainer.new()
panel.set_script(preload("res://scripts/ui/item_tooltip_frame.gd"))
var background := StyleBoxFlat.new() var background := StyleBoxFlat.new()
background.bg_color = Color("101925") background.bg_color = Color("101925")
background.border_color = Color("52677e") background.border_color = Color("52677e")
background.set_border_width_all(1) background.set_border_width_all(1)
background.border_width_top = 2
background.set_content_margin_all(12) background.set_content_margin_all(12)
background.set_corner_radius_all(3)
background.shadow_size = 0
panel.add_theme_stylebox_override("panel", background) panel.add_theme_stylebox_override("panel", background)
var label := RichTextLabel.new() var label := RichTextLabel.new()
label.fit_content = true label.fit_content = true
label.scroll_active = false label.scroll_active = false
label.mouse_filter = Control.MOUSE_FILTER_IGNORE label.mouse_filter = Control.MOUSE_FILTER_IGNORE
label.custom_minimum_size.x = 330 label.custom_minimum_size.x = 290
label.size.x = 290
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.add_theme_font_size_override("normal_font_size", 13) label.add_theme_font_size_override("normal_font_size", 11)
label.add_theme_constant_override("line_separation", -2)
label.add_theme_color_override("default_color", Color("c4d2df"))
var item := _inventory.get_item(slot_kind, slot_index) var item := _inventory.get_item(slot_kind, slot_index)
if item: if item:
background.bg_color = item.get_background_color() # Dark neutral body with an accent tied to the equipment category.
background.bg_color = Color("0c1520").lerp(item.get_background_color().darkened(0.8), 0.25)
background.border_color = item.get_type_color() background.border_color = item.get_type_color()
label.add_theme_color_override("default_color", Color("f1f4f8")) panel.set("accent", item.get_type_color())
for line in for_text.split("\n"): var columns := HBoxContainer.new()
columns.add_theme_constant_override("separation", 12)
panel.add_child(columns)
var details := VBoxContainer.new()
details.custom_minimum_size.x = 290
details.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
details.add_theme_constant_override("separation", 8)
columns.add_child(details)
var lines := for_text.split("\n")
if item != null:
var header_frame := PanelContainer.new()
var header_style := StyleBoxFlat.new()
header_style.bg_color = item.get_type_color().darkened(0.8)
header_style.border_color = item.get_type_color().darkened(0.35)
header_style.border_width_left = 3
header_style.set_content_margin_all(8)
header_frame.add_theme_stylebox_override("panel", header_style)
details.add_child(header_frame)
var header := HBoxContainer.new()
header.add_theme_constant_override("separation", 10)
header_frame.add_child(header)
if item.definition.icon != null:
var icon := TextureRect.new()
icon.texture = item.definition.icon
icon.custom_minimum_size = Vector2(54, 54)
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
header.add_child(icon)
var heading := VBoxContainer.new()
heading.size_flags_horizontal = Control.SIZE_EXPAND_FILL
heading.add_theme_constant_override("separation", 2)
header.add_child(heading)
var title := _comparison_label(item.definition.display_name, 0, Color("f1f4f8"))
title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
title.add_theme_font_size_override("font_size", 13)
heading.add_child(title)
heading.add_child(_comparison_label("%s · POZ. %d" % [item.get_rarity_name(), item.item_level], 0, item.get_type_color().lightened(0.25)))
heading.add_child(_comparison_label("%s · ADDONY: %d/5" % [_category_name(item.definition.category), item.get_addon_count()], 0, Color("8ba2b7")))
lines = lines.slice(2)
while not lines.is_empty() and lines[0].is_empty():
lines.remove_at(0)
details.add_child(label)
for line in lines:
if line == "CECHA GŁÓWNA" or line.contains("ADDONY (aktywne"):
label.push_font_size(10)
label.push_color(Color("91dbea"))
label.add_text("PARAMETRY\n" if line == "CECHA GŁÓWNA" else "ADDONY · PO ZAMONTOWANIU\n")
label.pop()
label.pop()
continue
var quality := 0 var quality := 0
var is_addon := false
if item: if item:
for modifier in item.additional_modifiers: for modifier in item.additional_modifiers:
if modifier != null and line == modifier.get_display_text(): if modifier != null and line == modifier.get_display_text():
is_addon = true
quality = modifier.get_roll_quality(item.item_level) quality = modifier.get_roll_quality(item.item_level)
break break
if quality > 0: var color := Color("ffd166") if quality == 2 else (Color("79e6a0") if quality == 1 else Color("c4d2df"))
label.push_color(Color("ffd166") if quality == 2 else Color("79e6a0")) if line.begins_with("Obrażenia:"):
label.add_text(("★ " if quality == 2 else "") + line + "\n") label.push_font_size(13)
if quality > 0: color = Color("ffd166")
if line.begins_with("Typ obrażeń:"):
color = [Color("efb568"), Color("91dbea"), Color("a9ef83")][item.definition.get_damage_type()] if item != null else Color("e6f2fc")
if line.begins_with("Każdy strzał"):
color = Color("8298ad")
label.push_color(color)
label.add_text(("★ " if quality == 2 else ("• " if is_addon else "")) + line + "\n")
label.pop()
if line.begins_with("Obrażenia:"):
label.pop() label.pop()
var columns := HBoxContainer.new()
columns.add_theme_constant_override("separation", 16)
panel.add_child(columns)
columns.add_child(label)
if slot_kind == "cargo" and item != null: if slot_kind == "cargo" and item != null:
_add_comparison_column(columns, item) _add_comparison_column(columns, item)
# Wrapped text can become shorter after the first layout pass.
panel.minimum_size_changed.connect(func() -> void: panel.reset_size.call_deferred())
panel.reset_size.call_deferred()
return panel return panel
func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void: func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
@ -185,13 +251,18 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
comparison.fit_content = true comparison.fit_content = true
comparison.scroll_active = false comparison.scroll_active = false
comparison.mouse_filter = Control.MOUSE_FILTER_IGNORE comparison.mouse_filter = Control.MOUSE_FILTER_IGNORE
comparison.custom_minimum_size.x = 290 comparison.custom_minimum_size.x = 270
comparison.size.x = 270
comparison.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART comparison.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
comparison.add_theme_font_size_override("normal_font_size", 13) comparison.add_theme_font_size_override("normal_font_size", 11)
comparison.add_theme_color_override("default_color", Color("f1f4f8")) comparison.add_theme_constant_override("line_separation", -2)
comparison.add_theme_color_override("default_color", Color("c4d2df"))
comparison.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
columns.add_child(comparison) columns.add_child(comparison)
var equipped := _inventory.get_item("module", module_index) var equipped := _inventory.get_item("module", module_index)
comparison.push_color(Color("91dbea"))
comparison.add_text("ZMIANY PO ZAŁOŻENIU\n") comparison.add_text("ZMIANY PO ZAŁOŻENIU\n")
comparison.pop()
comparison.add_text("Slot: %s\n" % ShipInventory.MODULE_NAMES[module_index]) comparison.add_text("Slot: %s\n" % ShipInventory.MODULE_NAMES[module_index])
comparison.add_text("Obecnie: %s\n\n" % ("%s • Poz. %d" % [equipped.definition.display_name, equipped.item_level] if equipped != null else "pusty")) comparison.add_text("Obecnie: %s\n\n" % ("%s • Poz. %d" % [equipped.definition.display_name, equipped.item_level] if equipped != null else "pusty"))
comparison.add_text("Zmiana statystyk statku:\n") comparison.add_text("Zmiana statystyk statku:\n")
@ -203,13 +274,17 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
var name: String = row["name"] var name: String = row["name"]
comparison.add_text("%s: %+.2f %s\n" % [name, row["delta"], row["unit"]]) comparison.add_text("%s: %+.2f %s\n" % [name, row["delta"], row["unit"]])
comparison.pop() comparison.pop()
comparison.push_color(Color("8298ad"))
comparison.push_font_size(10)
comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.") comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.")
comparison.pop()
comparison.pop()
func _comparison_label(text_value: String, width: float, color: Color = Color("f1f4f8")) -> Label: func _comparison_label(text_value: String, width: float, color: Color = Color("f1f4f8")) -> Label:
var label := Label.new() var label := Label.new()
label.text = text_value label.text = text_value
label.custom_minimum_size.x = width label.custom_minimum_size.x = width
label.add_theme_font_size_override("font_size", 11) label.add_theme_font_size_override("font_size", 10)
label.add_theme_color_override("font_color", color) label.add_theme_color_override("font_color", color)
label.mouse_filter = Control.MOUSE_FILTER_IGNORE label.mouse_filter = Control.MOUSE_FILTER_IGNORE
return label return label

View File

@ -32,34 +32,34 @@ func _draw() -> void:
closed.append(outline[0]) closed.append(outline[0])
draw_polyline(closed, Color("376779"), 1.5, true) draw_polyline(closed, Color("376779"), 1.5, true)
draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true) draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true)
_text("DPS: %.1f · GAMMA: %d" % [_inventory.get_total_dps(), _inventory.irradiated_ammunition], Vector2(20, 143), size.x - 40, 12, CYAN) # Put weapon cards beside the counters rather than stacking three rows.
_text(DamageTypes.describe(player.get("absorption")), Vector2(20, 162), size.x - 40, 10, Color("a9d69a")) _text("DPS: %.1f" % _inventory.get_total_dps(), Vector2(20, 81), 172, 12, CYAN)
var cell := (size.x - 40) / 3.0 _text(DamageTypes.describe(player.get("absorption")), Vector2(205, 81), size.x - 225, 11, Color("a9d69a"))
var cell := (size.x - 238) / 3.0
var values := [_inventory.missile_ammunition, _inventory.ammunition, int(game.call("get_remaining_enemies"))] var values := [_inventory.missile_ammunition, _inventory.ammunition, int(game.call("get_remaining_enemies"))]
var captions := ["RAKIETY", "AMUNICJA", "WROGOWIE"] var captions := ["RAKIETY", "AMUNICJA", "WROGOWIE"]
for index in 3: for index in 3:
var x := 20.0 + index * cell var x := 218.0 + index * cell
var color := AMBER if index == 0 else (CYAN if index == 1 else Color("ff8989")) var color := AMBER if index == 0 else (CYAN if index == 1 else Color("ff8989"))
_text(captions[index], Vector2(x, 21), cell, 9, Color("8aa9bb")) _text(captions[index], Vector2(x, 21), cell, 9, Color("8aa9bb"))
_text(str(values[index]).pad_zeros(2), Vector2(x, 45), cell, 21, color) if index == 1:
_text("ZWYKŁE %02d" % _inventory.ammunition, Vector2(x, 35), cell, 11, CYAN)
_text("GAMMA %02d" % _inventory.irradiated_ammunition, Vector2(x, 49), cell, 11, Color("a9ef83"))
else:
_text(str(values[index]).pad_zeros(2), Vector2(x, 45), cell, 21, color)
if index < 2: if index < 2:
draw_line(Vector2(x + cell, 14), Vector2(x + cell, 45), Color("2b4354"), 1) draw_line(Vector2(x + cell, 14), Vector2(x + cell, 45), Color("2b4354"), 1)
var card := Rect2(x + cell * 0.5 - 32, 52, 64, 64) var card := Rect2(20 + index * 60, 12, 52, 52)
var slot_index: int = WEAPON_DISPLAY_ORDER[index] var slot_index: int = WEAPON_DISPLAY_ORDER[index]
var item := _inventory.weapon_slots[slot_index] var item := _inventory.weapon_slots[slot_index]
var border := item.get_type_color() if item != null else Color("344657") var border := item.get_type_color() if item != null else Color("344657")
draw_style_box(_card_style(border), card) draw_style_box(_card_style(border), card)
var binding: String = ["LPM", "PPM", "ŚPM"][slot_index] var binding: String = ["LPM", "PPM", "ŚPM"][slot_index]
_text(binding, card.position + Vector2(0, 14), card.size.x, 9, CYAN) _text(binding, card.position + Vector2(0, 12), card.size.x, 9, CYAN)
if item != null and item.definition.icon != null: if item != null and item.definition.icon != null:
draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(11, 18), Vector2(42, 42)), false) draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(9, 16), Vector2(34, 34)), false)
else: else:
_text("—", card.position + Vector2(0, 40), card.size.x, 14, Color("637d90")) _text("—", card.position + Vector2(0, 36), card.size.x, 14, Color("637d90"))
var ratio := float(player.get(["hull", "shields", "energy"][index])) / maxf(1, float(player.get(["max_hull", "max_shields", "max_energy"][index])))
var gauge := Rect2(x + 5, 121, cell - 10, 3)
draw_rect(gauge, Color("172632"))
gauge.size.x *= clampf(ratio, 0, 1)
draw_rect(gauge, [Color("ea9277"), CYAN, AMBER][index])
func _card_style(color: Color) -> StyleBoxFlat: func _card_style(color: Color) -> StyleBoxFlat:
var style := StyleBoxFlat.new() var style := StyleBoxFlat.new()

View File

@ -0,0 +1,30 @@
extends RefCounted
static func apply(button: Button, accent: Color = Color("91dbea")) -> void:
button.focus_mode = Control.FOCUS_NONE
button.add_theme_font_size_override("font_size", 12)
button.add_theme_color_override("font_color", accent.lightened(0.25))
button.add_theme_color_override("font_hover_color", Color.WHITE)
button.add_theme_color_override("font_pressed_color", Color.WHITE)
button.add_theme_color_override("font_disabled_color", Color("566b7d"))
button.add_theme_stylebox_override("normal", _style(Color("10212e"), accent.darkened(0.45)))
button.add_theme_stylebox_override("hover", _style(Color("193446"), accent))
button.add_theme_stylebox_override("pressed", _style(accent.darkened(0.72), accent.lightened(0.15)))
button.add_theme_stylebox_override("disabled", _style(Color("101820"), Color("2c3b46")))
button.add_theme_constant_override("outline_size", 0)
static func _style(background: Color, border: Color) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = background
style.border_color = border
style.set_border_width_all(1)
style.border_width_left = 3
style.set_corner_radius_all(7)
style.content_margin_left = 14
style.content_margin_right = 14
style.content_margin_top = 6
style.content_margin_bottom = 6
style.shadow_color = Color(0, 0, 0, 0.24)
style.shadow_size = 3
style.shadow_offset = Vector2(0, 2)
return style

View File

@ -0,0 +1 @@
uid://c8mg5jsryv3ig

View File

@ -0,0 +1,71 @@
extends PanelContainer
var resource_name := ""
var description := ""
var accent := Color("91dbea")
var icon_texture: Texture2D
var _count: Label
func _ready() -> void:
custom_minimum_size = Vector2(86, 44)
size_flags_horizontal = Control.SIZE_EXPAND_FILL
var style := _style(false)
add_theme_stylebox_override("panel", style)
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 5)
add_child(row)
var icon := TextureRect.new()
icon.texture = icon_texture
icon.custom_minimum_size = Vector2(32, 32)
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.add_child(icon)
_count = Label.new()
_count.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_count.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
_count.add_theme_font_size_override("font_size", 11)
_count.add_theme_color_override("font_color", accent.lightened(0.2))
_count.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.add_child(_count)
row.mouse_filter = Control.MOUSE_FILTER_IGNORE
mouse_entered.connect(func() -> void: add_theme_stylebox_override("panel", _style(true)))
mouse_exited.connect(func() -> void: add_theme_stylebox_override("panel", _style(false)))
set_amount(0)
func _style(hovered: bool) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color("172737") if hovered else Color("0c1723")
style.border_color = accent if hovered else accent.darkened(0.65)
style.set_border_width_all(1)
style.set_corner_radius_all(4)
style.content_margin_left = 6
style.content_margin_right = 6
style.content_margin_top = 5
style.content_margin_bottom = 5
return style
func set_amount(amount: float) -> void:
if _count == null:
return
_count.text = str(roundi(amount)) if is_equal_approx(amount, roundf(amount)) else "%.1f" % amount
tooltip_text = "%s\n%s\nZapas: %s" % [resource_name, description, _count.text]
func _make_custom_tooltip(_text: String) -> Object:
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", _style(true))
var contents := VBoxContainer.new()
contents.add_theme_constant_override("separation", 4)
panel.add_child(contents)
var title := Label.new()
title.text = resource_name
title.add_theme_font_size_override("font_size", 12)
title.add_theme_color_override("font_color", accent)
contents.add_child(title)
var body := Label.new()
body.text = description + "\nZapas: " + _count.text
body.custom_minimum_size.x = 240
body.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
body.add_theme_font_size_override("font_size", 10)
contents.add_child(body)
return panel

View File

@ -0,0 +1 @@
uid://c7o65mkccm8vf

View File

@ -0,0 +1,30 @@
extends PanelContainer
var accent := Color("91dbea")
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
z_index = 1
resized.connect(queue_redraw)
minimum_size_changed.connect(func() -> void: _fit_popup.call_deferred())
_fit_popup.call_deferred()
func _fit_popup() -> void:
reset_size()
var shell := get_parent()
if shell is Control and shell.get_parent() is Window:
shell.reset_size()
shell = shell.get_parent()
if shell is Window:
# The engine popup otherwise retains its first, unwrapped text height.
shell.size = Vector2i(get_combined_minimum_size().ceil()) + Vector2i(4, 4)
func _draw() -> void:
# Crisp etched corner brackets and a top accent; no blurred shadow.
var inset := 5.0
var length := 12.0
for corner in [Vector2(inset, inset), Vector2(size.x - inset, inset), Vector2(inset, size.y - inset), Vector2(size.x - inset, size.y - inset)]:
var inward := Vector2(1 if corner.x < size.x * 0.5 else -1, 1 if corner.y < size.y * 0.5 else -1)
draw_line(corner, corner + Vector2(inward.x * length, 0), accent, 1.5, true)
draw_line(corner, corner + Vector2(0, inward.y * length), accent, 1.5, true)
draw_line(Vector2(22, 1), Vector2(minf(size.x - 22, 112), 1), accent, 2, true)

View File

@ -0,0 +1 @@
uid://dtfbtajrculf0

View File

@ -22,7 +22,7 @@ func _ready() -> void:
_toggle.text = "TWÓRZ ▾" _toggle.text = "TWÓRZ ▾"
_toggle.custom_minimum_size.y = 28 _toggle.custom_minimum_size.y = 28
_toggle.add_theme_font_size_override("font_size", 12) _toggle.add_theme_font_size_override("font_size", 12)
_toggle.focus_mode = Control.FOCUS_NONE preload("res://scripts/ui/hud_button_style.gd").apply(_toggle, Color("efb568"))
_toggle.pressed.connect(_toggle_expanded) _toggle.pressed.connect(_toggle_expanded)
contents.add_child(_toggle) contents.add_child(_toggle)
_details = VBoxContainer.new() _details = VBoxContainer.new()

View File

@ -6,20 +6,18 @@ const CARGO_SIZE := 20
@onready var cargo_grid: GridContainer = $Contents/CargoGrid @onready var cargo_grid: GridContainer = $Contents/CargoGrid
@onready var close_button: Button = $Contents/Header/CloseButton @onready var close_button: Button = $Contents/Header/CloseButton
@onready var title_label: Label = $Contents/Header/Title @onready var title_label: Label = $Contents/Header/Title
@onready var ammunition_label: Label = $Contents/Ammunition/Count
var _inventory: ShipInventory var _inventory: ShipInventory
var _drawer_open := false var _drawer_open := false
var _slide_tween: Tween var _slide_tween: Tween
var _minerals_label: Label var _resource_cards: Dictionary = {}
var drawer_width := 560.0 var drawer_width := 560.0
func _ready() -> void: func _ready() -> void:
close_button.pressed.connect(close_drawer) close_button.pressed.connect(close_drawer)
_minerals_label = Label.new() preload("res://scripts/ui/hud_button_style.gd").apply(close_button, Color("91dbea"))
_minerals_label.add_theme_font_size_override("font_size", 10) close_button.add_theme_font_size_override("font_size", 10)
$Contents.add_child(_minerals_label) _create_resource_section()
$Contents.move_child(_minerals_label, $Contents/CargoGrid.get_index())
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory _inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
if _inventory: if _inventory:
_inventory.inventory_changed.connect(_refresh_title) _inventory.inventory_changed.connect(_refresh_title)
@ -34,11 +32,75 @@ func _ready() -> void:
_refresh_title() _refresh_title()
func _refresh_title() -> void: func _refresh_title() -> void:
_minerals_label.text = "SUROWCE · Tytan: %d · Żelazo: %d · Aluminium: %d" % [GameState.captain.minerals.get("titanium", 0), GameState.captain.minerals.get("iron", 0), GameState.captain.minerals.get("aluminium", 0)] for key in ["iron", "titanium", "aluminium", "uranium"]:
_resource_cards[key].set_amount(float(GameState.captain.minerals.get(key, 0)))
_resource_cards["parts"].set_amount(GameState.captain.parts)
if _inventory: if _inventory:
title_label.text = "MAGAZYN (%d/%d) · Części: %.1f" % [_inventory.get_cargo_used(), CARGO_SIZE, GameState.captain.parts] title_label.text = "MAGAZYN · %d / %d" % [_inventory.get_cargo_used(), CARGO_SIZE]
ammunition_label.text = "AMUNICJA: %d · RAKIETY: %d" % [_inventory.ammunition, _inventory.get_missile_count()] _resource_cards["ammunition"].set_amount(_inventory.ammunition)
ammunition_label.text += " · GAMMA: %d" % _inventory.irradiated_ammunition _resource_cards["irradiated_ammunition"].set_amount(_inventory.irradiated_ammunition)
_resource_cards["missile"].set_amount(_inventory.get_missile_count())
func _create_resource_section() -> void:
var frame := PanelContainer.new()
frame.name = "ResourceSection"
var style := StyleBoxFlat.new()
style.bg_color = Color("101e2d")
style.border_color = Color("2d4c60")
style.set_border_width_all(1)
style.set_corner_radius_all(5)
style.set_content_margin_all(8)
frame.add_theme_stylebox_override("panel", style)
$Contents.add_child(frame)
$Contents.move_child(frame, cargo_grid.get_index())
var section := VBoxContainer.new()
section.name = "Resources"
section.add_theme_constant_override("separation", 6)
frame.add_child(section)
var minerals := _resource_row(section, "SUROWCE", Color("d4b58a"))
for data in [
["iron", "Żelazo", "Surowiec pozyskiwany z asteroid.", Color("c5b5a0")],
["titanium", "Tytan", "Surowiec pozyskiwany z asteroid.", Color("9ecbe9")],
["aluminium", "Aluminium", "Surowiec pozyskiwany z asteroid.", Color("dce8ef")],
["uranium", "Uran", "Surowiec z asteroid. Do produkcji napromieniowanej amunicji.", Color("a9ef83")],
["parts", "Części", "Odzyskiwane z przedmiotów i wraków. Do produkcji amunicji i napraw.", Color("efb568")],
]:
_add_resource_card(minerals, data)
var ammunition := _resource_row(section, "AMUNICJA", Color("91dbea"))
for data in [
["ammunition", "Zwykła amunicja", "Pociski do działka maszynowego. Obrażenia kinetyczne.", Color("efb568")],
["irradiated_ammunition", "Napromieniowana amunicja", "Kapsuły do działka gamma. Obrażenia radiacyjne.", Color("a9ef83")],
["missile", "Rakiety", "Amunicja do wyrzutni rakiet. Obrażenia kinetyczne.", Color("ffac8b")],
]:
_add_resource_card(ammunition, data)
var cargo_title := Label.new()
cargo_title.text = "PRZEDMIOTY"
cargo_title.add_theme_font_size_override("font_size", 10)
cargo_title.add_theme_color_override("font_color", Color("91dbea"))
$Contents.add_child(cargo_title)
$Contents.move_child(cargo_title, cargo_grid.get_index())
func _resource_row(section: VBoxContainer, caption: String, color: Color) -> HBoxContainer:
var title := Label.new()
title.text = caption
title.add_theme_font_size_override("font_size", 10)
title.add_theme_color_override("font_color", color)
section.add_child(title)
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 5)
section.add_child(row)
return row
func _add_resource_card(row: HBoxContainer, data: Array) -> void:
var card := PanelContainer.new()
card.set_script(preload("res://scripts/ui/inventory_resource_card.gd"))
card.name = str(data[0]).to_pascal_case()
card.set("resource_name", data[1])
card.set("description", data[2])
card.set("accent", data[3])
card.set("icon_texture", load("res://assets/icons/resources/%s.png" % data[0]))
row.add_child(card)
_resource_cards[data[0]] = card
func toggle_drawer() -> void: func toggle_drawer() -> void:
_set_drawer_open(not _drawer_open) _set_drawer_open(not _drawer_open)

View File

@ -0,0 +1,32 @@
extends Node2D
func _ready() -> void:
GameState.start_new_run()
seed(56789)
var ship := preload("res://scenes/game/player_ship.tscn").instantiate()
add_child(ship)
ship.set_physics_process(false)
ship.get_node("WeaponController").set_physics_process(false)
ship.shields = 1000.0
ship.max_shields = 1000.0
var enemy := preload("res://scenes/game/enemy_ship.tscn").instantiate()
enemy.position = Vector2(400, 0)
add_child(enemy)
enemy.set_physics_process(false)
enemy.set("_player", ship)
enemy.weapon_kind = ItemDefinition.WeaponKind.LASER
enemy.weapon_damage = 1.0
enemy.weapon_cooldown = 1.5
assert(is_equal_approx(enemy.get_fire_interval(), 3.0))
assert(is_equal_approx(enemy.get_weapon_dps(), 1.0 / 3.0))
enemy.weapon_cooldown = 0.275
assert(enemy.get_fire_interval() >= 1.4)
await get_tree().physics_frame
await get_tree().physics_frame
for index in 100:
enemy._fire_plasma(Vector2.LEFT)
var hits := 1000.0 - float(ship.shields)
assert(hits >= 45.0 and hits <= 85.0)
print("ENEMY_LASER_TEST: PASS (slower cooldown, minimum interval, displayed DPS, %d real hits / 100 shots)" % roundi(hits))
await get_tree().create_timer(0.15).timeout
get_tree().quit()

View File

@ -0,0 +1 @@
uid://ca6c7s2fwiptt

View File

@ -0,0 +1,4 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://tests/items/enemy_laser_test.gd" id="1"]
[node name="EnemyLaserTest" type="Node2D"]
script = ExtResource("1")

View File

@ -5,6 +5,7 @@ func _ready() -> void:
GameState.start_new_run() GameState.start_new_run()
GameState.system_seed = 314159 GameState.system_seed = 314159
var game := GAME.instantiate() var game := GAME.instantiate()
assert(game.BOSS_SPAWN_DISTANCE >= 1800.0)
add_child(game) add_child(game)
game.set_physics_process(false) game.set_physics_process(false)
var player: CharacterBody2D = game.get_node("PlayerShip") var player: CharacterBody2D = game.get_node("PlayerShip")