diff --git a/assets/icons/gamma.png b/assets/icons/gamma.png new file mode 100644 index 0000000..0a3ae6a Binary files /dev/null and b/assets/icons/gamma.png differ diff --git a/assets/icons/gamma.png.import b/assets/icons/gamma.png.import new file mode 100644 index 0000000..58afcd0 --- /dev/null +++ b/assets/icons/gamma.png.import @@ -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 diff --git a/assets/icons/gamma.prompt.md b/assets/icons/gamma.prompt.md new file mode 100644 index 0000000..7c559fc --- /dev/null +++ b/assets/icons/gamma.prompt.md @@ -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. diff --git a/assets/icons/resources/aluminium.png b/assets/icons/resources/aluminium.png new file mode 100644 index 0000000..351634d Binary files /dev/null and b/assets/icons/resources/aluminium.png differ diff --git a/assets/icons/resources/aluminium.png.import b/assets/icons/resources/aluminium.png.import new file mode 100644 index 0000000..a320871 --- /dev/null +++ b/assets/icons/resources/aluminium.png.import @@ -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 diff --git a/assets/icons/resources/ammunition.png b/assets/icons/resources/ammunition.png new file mode 100644 index 0000000..c55f585 Binary files /dev/null and b/assets/icons/resources/ammunition.png differ diff --git a/assets/icons/resources/ammunition.png.import b/assets/icons/resources/ammunition.png.import new file mode 100644 index 0000000..8739f9b --- /dev/null +++ b/assets/icons/resources/ammunition.png.import @@ -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 diff --git a/assets/icons/resources/iron.png b/assets/icons/resources/iron.png new file mode 100644 index 0000000..9e25070 Binary files /dev/null and b/assets/icons/resources/iron.png differ diff --git a/assets/icons/resources/iron.png.import b/assets/icons/resources/iron.png.import new file mode 100644 index 0000000..1c0e825 --- /dev/null +++ b/assets/icons/resources/iron.png.import @@ -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 diff --git a/assets/icons/resources/irradiated_ammunition.png b/assets/icons/resources/irradiated_ammunition.png new file mode 100644 index 0000000..22d1a2d Binary files /dev/null and b/assets/icons/resources/irradiated_ammunition.png differ diff --git a/assets/icons/resources/irradiated_ammunition.png.import b/assets/icons/resources/irradiated_ammunition.png.import new file mode 100644 index 0000000..37412da --- /dev/null +++ b/assets/icons/resources/irradiated_ammunition.png.import @@ -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 diff --git a/assets/icons/resources/missile.png b/assets/icons/resources/missile.png new file mode 100644 index 0000000..cafdcac Binary files /dev/null and b/assets/icons/resources/missile.png differ diff --git a/assets/icons/resources/missile.png.import b/assets/icons/resources/missile.png.import new file mode 100644 index 0000000..c8a5a2a --- /dev/null +++ b/assets/icons/resources/missile.png.import @@ -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 diff --git a/assets/icons/resources/parts.png b/assets/icons/resources/parts.png new file mode 100644 index 0000000..0416de8 Binary files /dev/null and b/assets/icons/resources/parts.png differ diff --git a/assets/icons/resources/parts.png.import b/assets/icons/resources/parts.png.import new file mode 100644 index 0000000..1ece459 --- /dev/null +++ b/assets/icons/resources/parts.png.import @@ -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 diff --git a/assets/icons/resources/prompts.json b/assets/icons/resources/prompts.json new file mode 100644 index 0000000..bff9772 --- /dev/null +++ b/assets/icons/resources/prompts.json @@ -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" + } + ] +} diff --git a/assets/icons/resources/titanium.png b/assets/icons/resources/titanium.png new file mode 100644 index 0000000..14e7bd9 Binary files /dev/null and b/assets/icons/resources/titanium.png differ diff --git a/assets/icons/resources/titanium.png.import b/assets/icons/resources/titanium.png.import new file mode 100644 index 0000000..e9bab78 --- /dev/null +++ b/assets/icons/resources/titanium.png.import @@ -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 diff --git a/assets/icons/resources/uranium.png b/assets/icons/resources/uranium.png new file mode 100644 index 0000000..220a615 Binary files /dev/null and b/assets/icons/resources/uranium.png differ diff --git a/assets/icons/resources/uranium.png.import b/assets/icons/resources/uranium.png.import new file mode 100644 index 0000000..e85431f --- /dev/null +++ b/assets/icons/resources/uranium.png.import @@ -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 diff --git a/resources/items/gamma_cannon.tres b/resources/items/gamma_cannon.tres index 0fa1c74..dd56998 100644 --- a/resources/items/gamma_cannon.tres +++ b/resources/items/gamma_cannon.tres @@ -1,6 +1,6 @@ [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="Texture2D" path="res://assets/icons/gamma.svg" id="icon"] +[ext_resource type="Texture2D" path="res://assets/icons/gamma.png" id="icon"] [resource] script = ExtResource("1") icon = ExtResource("icon") diff --git a/resources/ui/game_theme.tres b/resources/ui/game_theme.tres index 77d66eb..57d22f5 100644 --- a/resources/ui/game_theme.tres +++ b/resources/ui/game_theme.tres @@ -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"] +[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] default_font = ExtResource("1_font") +TooltipPanel/styles/panel = SubResource("TooltipShell") +TooltipLabel/font_sizes/font_size = 11 diff --git a/scenes/ui/planet_services_menu.tscn b/scenes/ui/planet_services_menu.tscn index 9325d97..4712420 100644 --- a/scenes/ui/planet_services_menu.tscn +++ b/scenes/ui/planet_services_menu.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"] [sub_resource type="StyleBoxFlat" id="PanelStyle"] -bg_color = Color(0.045, 0.075, 0.11, 1) +bg_color = Color(0.045, 0.075, 0.11, 0.64) border_width_left = 1 border_width_top = 1 border_width_right = 1 diff --git a/scenes/ui/ship_equipment_panel.tscn b/scenes/ui/ship_equipment_panel.tscn index ccd7920..cddb05c 100644 --- a/scenes/ui/ship_equipment_panel.tscn +++ b/scenes/ui/ship_equipment_panel.tscn @@ -43,7 +43,7 @@ text = "SYSTEMY POKŁADOWE" horizontal_alignment = 1 [node name="EquipmentLayout" type="Control" parent="Contents"] -custom_minimum_size = Vector2(284, 456) +custom_minimum_size = Vector2(284, 552) layout_mode = 2 mouse_filter = 2 @@ -100,9 +100,9 @@ overlay_slot = true [node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 14.0 -offset_top = 178.0 +offset_top = 200.0 offset_right = 78.0 -offset_bottom = 242.0 +offset_bottom = 264.0 slot_kind = "module" slot_index = 1 overlay_slot = true @@ -110,9 +110,9 @@ overlay_slot = true [node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 14.0 -offset_top = 248.0 +offset_top = 292.0 offset_right = 78.0 -offset_bottom = 312.0 +offset_bottom = 356.0 slot_kind = "module" slot_index = 2 overlay_slot = true @@ -120,9 +120,9 @@ overlay_slot = true [node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 14.0 -offset_top = 318.0 +offset_top = 384.0 offset_right = 78.0 -offset_bottom = 382.0 +offset_bottom = 448.0 slot_kind = "module" slot_index = 3 overlay_slot = true @@ -130,9 +130,9 @@ overlay_slot = true [node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 14.0 -offset_top = 388.0 +offset_top = 476.0 offset_right = 78.0 -offset_bottom = 452.0 +offset_bottom = 540.0 slot_kind = "module" slot_index = 4 overlay_slot = true @@ -150,9 +150,9 @@ overlay_slot = true [node name="Extension2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 206.0 -offset_top = 178.0 +offset_top = 200.0 offset_right = 270.0 -offset_bottom = 242.0 +offset_bottom = 264.0 slot_kind = "extension" slot_index = 1 overlay_slot = true @@ -160,9 +160,9 @@ overlay_slot = true [node name="Extension3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 206.0 -offset_top = 248.0 +offset_top = 292.0 offset_right = 270.0 -offset_bottom = 312.0 +offset_bottom = 356.0 slot_kind = "extension" slot_index = 2 overlay_slot = true @@ -170,9 +170,9 @@ overlay_slot = true [node name="Extension4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 206.0 -offset_top = 318.0 +offset_top = 384.0 offset_right = 270.0 -offset_bottom = 382.0 +offset_bottom = 448.0 slot_kind = "extension" slot_index = 3 overlay_slot = true @@ -180,9 +180,9 @@ overlay_slot = true [node name="Extension5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")] layout_mode = 0 offset_left = 206.0 -offset_top = 388.0 +offset_top = 476.0 offset_right = 270.0 -offset_bottom = 452.0 +offset_bottom = 540.0 slot_kind = "extension" slot_index = 4 overlay_slot = true diff --git a/scenes/ui/ship_inventory_panel.tscn b/scenes/ui/ship_inventory_panel.tscn index 143e940..06b6061 100644 --- a/scenes/ui/ship_inventory_panel.tscn +++ b/scenes/ui/ship_inventory_panel.tscn @@ -49,16 +49,6 @@ layout_mode = 2 theme_override_font_sizes/font_size = 11 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"] layout_mode = 2 size_flags_horizontal = 4 diff --git a/scripts/game/enemy_ship.gd b/scripts/game/enemy_ship.gd index dcee445..74bdd7b 100644 --- a/scripts/game/enemy_ship.gd +++ b/scripts/game/enemy_ship.gd @@ -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_OFFSET := Vector2(0, 36) 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 @@ -40,7 +43,7 @@ func _ready() -> void: add_child(_shield_visual) _shield_visual.set_shield_values(shields, max_shields) 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: loot_tier = tier @@ -102,7 +105,7 @@ func _physics_process(delta: float) -> void: _weapon_timer = maxf(0.0, _weapon_timer - delta) if to_player.length() <= weapon_range and _weapon_timer <= 0.0: _fire_plasma(direction) - _weapon_timer = weapon_cooldown + _weapon_timer = get_fire_interval() else: velocity = velocity.move_toward(Vector2.ZERO, approach_acceleration * delta) @@ -118,7 +121,7 @@ func _check_player_collision() -> void: func _fire_plasma(direction: Vector2) -> void: var muzzle := global_position + direction * (get_visual_size() * 0.5 + 8.0) 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 hit := get_world_2d().direct_space_state.intersect_ray(query) if not hit.is_empty(): @@ -170,8 +173,22 @@ func take_damage(amount: float, critical: bool = false, damage_type: int = Damag _spawn_destruction_effect() 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: - 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: if is_instance_valid(_player): diff --git a/scripts/game/flight_hud.gd b/scripts/game/flight_hud.gd index 0c673c2..a4d9710 100644 --- a/scripts/game/flight_hud.gd +++ b/scripts/game/flight_hud.gd @@ -19,6 +19,9 @@ var _sidebar_tween: Tween const SIDEBAR_WIDTH := 306.0 const EQUIPMENT_UI_SCALE := 0.8 var _debug_scroll: ScrollContainer +var _debug_actions: VBoxContainer +var _debug_item_button: Button +var _debug_item_status: Label var _captain_panel: PanelContainer var _cockpit: Control @@ -70,6 +73,23 @@ func _create_sidebar() -> void: _captain_panel.position = Vector2(12, 12) _captain_panel.size = Vector2(320, _captain_panel.get_combined_minimum_size().y) _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.name = "DebugScroll" _debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED @@ -110,13 +130,14 @@ func _create_sidebar() -> void: _sidebar_toggle.name = "ShipToggle" _sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀" _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) _sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT) _sidebar_toggle.offset_left = -180 _sidebar_toggle.offset_right = -12 _sidebar_toggle.offset_top = 12 - _sidebar_toggle.offset_bottom = 40 + _sidebar_toggle.offset_bottom = 48 _sidebar_toggle.pressed.connect(_toggle_sidebar) _cockpit = Control.new() _cockpit.name = "Cockpit" @@ -131,8 +152,12 @@ func _layout_debug() -> void: return var top := _captain_panel.position.y + _captain_panel.size.y + 6.0 debug_toggle.position = Vector2(12, top) - _debug_scroll.position = Vector2(18, top + 30) - _debug_scroll.size = Vector2(310, maxf(40, $HUDRoot.size.y - top - 42)) + _debug_actions.position = Vector2(18, top + 30) + _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 func _toggle_sidebar() -> void: @@ -158,10 +183,14 @@ func _layout_sidebar() -> void: _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))) _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) + 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() - _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 _inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE _layout_inventory() @@ -177,6 +206,10 @@ func _process(_delta: float) -> void: _update_ability_bar() if not _debug_expanded: 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() debug_info.text = """POZIOM UKŁADU: %d WROGOWIE: %d @@ -200,7 +233,25 @@ func _toggle_debug() -> void: GameState.hud_panel_state["debug_expanded"] = _debug_expanded debug_info.visible = _debug_expanded _debug_scroll.visible = _debug_expanded + _debug_actions.visible = _debug_expanded _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: 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.offset_left = -120.0 panel.offset_right = 120.0 - panel.offset_top = -176.0 - panel.offset_bottom = -132.0 + panel.offset_top = -220.0 + panel.offset_bottom = -176.0 panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new()) _ability_bar = HBoxContainer.new() _ability_bar.name = "AbilityButtons" diff --git a/scripts/game/game.gd b/scripts/game/game.gd index b3aa220..50cadb7 100644 --- a/scripts/game/game.gd +++ b/scripts/game/game.gd @@ -10,7 +10,7 @@ const WORLD_SIZE := SYSTEM_GENERATOR.WORLD_SIZE const SERVICE_APPROACH_DISTANCE := 180.0 const WORMHOLE_PLANET_DISTANCE := 620.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 ENEMY_SCENE := preload("res://scenes/game/enemy_ship.tscn") const ENEMY_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES diff --git a/scripts/items/item_instance.gd b/scripts/items/item_instance.gd index 7976710..a05ecaa 100644 --- a/scripts/items/item_instance.gd +++ b/scripts/items/item_instance.gd @@ -88,7 +88,8 @@ func get_addon_count() -> int: return count 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: if definition == null: diff --git a/scripts/ui/enemy_drawer.gd b/scripts/ui/enemy_drawer.gd index fc10c77..f941204 100644 --- a/scripts/ui/enemy_drawer.gd +++ b/scripts/ui/enemy_drawer.gd @@ -22,7 +22,7 @@ func _ready() -> void: _panel.add_child(_label) _toggle = Button.new() _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) _toggle.pressed.connect(_toggle_drawer) _open = bool(GameState.hud_panel_state.get("enemy_open", false)) @@ -32,9 +32,9 @@ func _ready() -> void: func _layout() -> void: position.x = (get_viewport_rect().size.x - 390.0) * 0.5 _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.size = Vector2(130, 28) + _toggle.size = Vector2(130, 36) func _toggle_drawer() -> void: _open = not _open @@ -43,7 +43,7 @@ func _toggle_drawer() -> void: if _tween != null: _tween.kill() _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: var enemy: Node = null diff --git a/scripts/ui/equipment_slot_view.gd b/scripts/ui/equipment_slot_view.gd index c61318c..8f97932 100644 --- a/scripts/ui/equipment_slot_view.gd +++ b/scripts/ui/equipment_slot_view.gd @@ -59,7 +59,7 @@ func _ready() -> void: var binding := Label.new() 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.position = Vector2(2, -14) + binding.position = Vector2(2, -24) binding.add_theme_font_size_override("font_size", 9) binding.add_theme_color_override("font_color", Color("a0b2c4")) # 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: var panel := PanelContainer.new() + panel.set_script(preload("res://scripts/ui/item_tooltip_frame.gd")) var background := StyleBoxFlat.new() background.bg_color = Color("101925") background.border_color = Color("52677e") background.set_border_width_all(1) + background.border_width_top = 2 background.set_content_margin_all(12) + background.set_corner_radius_all(3) + background.shadow_size = 0 panel.add_theme_stylebox_override("panel", background) var label := RichTextLabel.new() label.fit_content = true label.scroll_active = false 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.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) 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() - label.add_theme_color_override("default_color", Color("f1f4f8")) - for line in for_text.split("\n"): + panel.set("accent", item.get_type_color()) + 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 is_addon := false if item: for modifier in item.additional_modifiers: if modifier != null and line == modifier.get_display_text(): + is_addon = true quality = modifier.get_roll_quality(item.item_level) break - if quality > 0: - label.push_color(Color("ffd166") if quality == 2 else Color("79e6a0")) - label.add_text(("★ " if quality == 2 else "") + line + "\n") - if quality > 0: + var color := Color("ffd166") if quality == 2 else (Color("79e6a0") if quality == 1 else Color("c4d2df")) + if line.begins_with("Obrażenia:"): + label.push_font_size(13) + 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() - 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: _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 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.scroll_active = false 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.add_theme_font_size_override("normal_font_size", 13) - comparison.add_theme_color_override("default_color", Color("f1f4f8")) + comparison.add_theme_font_size_override("normal_font_size", 11) + 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) var equipped := _inventory.get_item("module", module_index) + comparison.push_color(Color("91dbea")) 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("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") @@ -203,13 +274,17 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void: var name: String = row["name"] comparison.add_text("%s: %+.2f %s\n" % [name, row["delta"], row["unit"]]) comparison.pop() + comparison.push_color(Color("8298ad")) + comparison.push_font_size(10) 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: var label := Label.new() label.text = text_value 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.mouse_filter = Control.MOUSE_FILTER_IGNORE return label diff --git a/scripts/ui/flight_cockpit.gd b/scripts/ui/flight_cockpit.gd index 4392461..fa43c84 100644 --- a/scripts/ui/flight_cockpit.gd +++ b/scripts/ui/flight_cockpit.gd @@ -32,34 +32,34 @@ func _draw() -> void: closed.append(outline[0]) draw_polyline(closed, Color("376779"), 1.5, true) draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true) - _text("DPS: %.1f · GAMMA: %d" % [_inventory.get_total_dps(), _inventory.irradiated_ammunition], Vector2(20, 143), size.x - 40, 12, CYAN) - _text(DamageTypes.describe(player.get("absorption")), Vector2(20, 162), size.x - 40, 10, Color("a9d69a")) - var cell := (size.x - 40) / 3.0 + # Put weapon cards beside the counters rather than stacking three rows. + _text("DPS: %.1f" % _inventory.get_total_dps(), Vector2(20, 81), 172, 12, CYAN) + _text(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 captions := ["RAKIETY", "AMUNICJA", "WROGOWIE"] 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")) _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: 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 item := _inventory.weapon_slots[slot_index] var border := item.get_type_color() if item != null else Color("344657") draw_style_box(_card_style(border), card) var binding: String = ["LPM", "PPM", "ŚPM"][slot_index] - _text(binding, card.position + Vector2(0, 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: - 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: - _text("—", card.position + Vector2(0, 40), 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]) + _text("—", 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/hud_button_style.gd b/scripts/ui/hud_button_style.gd new file mode 100644 index 0000000..bbdc0d1 --- /dev/null +++ b/scripts/ui/hud_button_style.gd @@ -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 diff --git a/scripts/ui/hud_button_style.gd.uid b/scripts/ui/hud_button_style.gd.uid new file mode 100644 index 0000000..921c9e1 --- /dev/null +++ b/scripts/ui/hud_button_style.gd.uid @@ -0,0 +1 @@ +uid://c8mg5jsryv3ig diff --git a/scripts/ui/inventory_resource_card.gd b/scripts/ui/inventory_resource_card.gd new file mode 100644 index 0000000..0036bfc --- /dev/null +++ b/scripts/ui/inventory_resource_card.gd @@ -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 diff --git a/scripts/ui/inventory_resource_card.gd.uid b/scripts/ui/inventory_resource_card.gd.uid new file mode 100644 index 0000000..ac94543 --- /dev/null +++ b/scripts/ui/inventory_resource_card.gd.uid @@ -0,0 +1 @@ +uid://c7o65mkccm8vf diff --git a/scripts/ui/item_tooltip_frame.gd b/scripts/ui/item_tooltip_frame.gd new file mode 100644 index 0000000..ce7a03f --- /dev/null +++ b/scripts/ui/item_tooltip_frame.gd @@ -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) diff --git a/scripts/ui/item_tooltip_frame.gd.uid b/scripts/ui/item_tooltip_frame.gd.uid new file mode 100644 index 0000000..d7c220a --- /dev/null +++ b/scripts/ui/item_tooltip_frame.gd.uid @@ -0,0 +1 @@ +uid://dtfbtajrculf0 diff --git a/scripts/ui/ship_crafting_panel.gd b/scripts/ui/ship_crafting_panel.gd index 1447824..a9a06c3 100644 --- a/scripts/ui/ship_crafting_panel.gd +++ b/scripts/ui/ship_crafting_panel.gd @@ -22,7 +22,7 @@ func _ready() -> void: _toggle.text = "TWÓRZ ▾" _toggle.custom_minimum_size.y = 28 _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) contents.add_child(_toggle) _details = VBoxContainer.new() diff --git a/scripts/ui/ship_inventory_panel.gd b/scripts/ui/ship_inventory_panel.gd index d18d4ba..06378f3 100644 --- a/scripts/ui/ship_inventory_panel.gd +++ b/scripts/ui/ship_inventory_panel.gd @@ -6,20 +6,18 @@ const CARGO_SIZE := 20 @onready var cargo_grid: GridContainer = $Contents/CargoGrid @onready var close_button: Button = $Contents/Header/CloseButton @onready var title_label: Label = $Contents/Header/Title -@onready var ammunition_label: Label = $Contents/Ammunition/Count var _inventory: ShipInventory var _drawer_open := false var _slide_tween: Tween -var _minerals_label: Label +var _resource_cards: Dictionary = {} var drawer_width := 560.0 func _ready() -> void: close_button.pressed.connect(close_drawer) - _minerals_label = Label.new() - _minerals_label.add_theme_font_size_override("font_size", 10) - $Contents.add_child(_minerals_label) - $Contents.move_child(_minerals_label, $Contents/CargoGrid.get_index()) + preload("res://scripts/ui/hud_button_style.gd").apply(close_button, Color("91dbea")) + close_button.add_theme_font_size_override("font_size", 10) + _create_resource_section() _inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory if _inventory: _inventory.inventory_changed.connect(_refresh_title) @@ -34,11 +32,75 @@ func _ready() -> void: _refresh_title() 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: - title_label.text = "MAGAZYN (%d/%d) · Części: %.1f" % [_inventory.get_cargo_used(), CARGO_SIZE, GameState.captain.parts] - ammunition_label.text = "AMUNICJA: %d · RAKIETY: %d" % [_inventory.ammunition, _inventory.get_missile_count()] - ammunition_label.text += " · GAMMA: %d" % _inventory.irradiated_ammunition + title_label.text = "MAGAZYN · %d / %d" % [_inventory.get_cargo_used(), CARGO_SIZE] + _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()) + +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: _set_drawer_open(not _drawer_open) diff --git a/tests/items/enemy_laser_test.gd b/tests/items/enemy_laser_test.gd new file mode 100644 index 0000000..5894d6f --- /dev/null +++ b/tests/items/enemy_laser_test.gd @@ -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() diff --git a/tests/items/enemy_laser_test.gd.uid b/tests/items/enemy_laser_test.gd.uid new file mode 100644 index 0000000..41d3e31 --- /dev/null +++ b/tests/items/enemy_laser_test.gd.uid @@ -0,0 +1 @@ +uid://ca6c7s2fwiptt diff --git a/tests/items/enemy_laser_test.tscn b/tests/items/enemy_laser_test.tscn new file mode 100644 index 0000000..8d246de --- /dev/null +++ b/tests/items/enemy_laser_test.tscn @@ -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") diff --git a/tests/levels/boss_spawn_test.gd b/tests/levels/boss_spawn_test.gd index 053a306..ac78740 100644 --- a/tests/levels/boss_spawn_test.gd +++ b/tests/levels/boss_spawn_test.gd @@ -5,6 +5,7 @@ func _ready() -> void: GameState.start_new_run() GameState.system_seed = 314159 var game := GAME.instantiate() + assert(game.BOSS_SPAWN_DISTANCE >= 1800.0) add_child(game) game.set_physics_process(false) var player: CharacterBody2D = game.get_node("PlayerShip")