Compare commits
2 Commits
a0fd024c7b
...
24a58b60db
| Author | SHA1 | Date | |
|---|---|---|---|
| 24a58b60db | |||
| 6ce039021c |
BIN
assets/Ships/player/bastion.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
40
assets/Ships/player/bastion.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dvr81d4dwt6t0"
|
||||||
|
path="res://.godot/imported/bastion.png-15006c633cecef3ba43fa69c64e8c34d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/Ships/player/bastion.png"
|
||||||
|
dest_files=["res://.godot/imported/bastion.png-15006c633cecef3ba43fa69c64e8c34d.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
|
||||||
BIN
assets/Ships/player/szerszen.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
40
assets/Ships/player/szerszen.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://d3xmihoeil2k6"
|
||||||
|
path="res://.godot/imported/szerszen.png-e23ede0a372aa7e06ec1d33ee683770d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/Ships/player/szerszen.png"
|
||||||
|
dest_files=["res://.godot/imported/szerszen.png-e23ede0a372aa7e06ec1d33ee683770d.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
|
||||||
BIN
assets/Ships/player/wedrowiec.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
40
assets/Ships/player/wedrowiec.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://u26qmt4md8wa"
|
||||||
|
path="res://.godot/imported/wedrowiec.png-c336464cc226bb3133caac3cdec5a157.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/Ships/player/wedrowiec.png"
|
||||||
|
dest_files=["res://.godot/imported/wedrowiec.png-c336464cc226bb3133caac3cdec5a157.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
|
||||||
BIN
assets/Ships/player/zmija.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
40
assets/Ships/player/zmija.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cvnbaa77y2sim"
|
||||||
|
path="res://.godot/imported/zmija.png-40bffd0ae89f8efb16dd5e7cf79adc7c.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/Ships/player/zmija.png"
|
||||||
|
dest_files=["res://.godot/imported/zmija.png-40bffd0ae89f8efb16dd5e7cf79adc7c.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
|
||||||
BIN
assets/icons/afterburner.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
40
assets/icons/afterburner.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://kukr8bhgqa7p"
|
||||||
|
path="res://.godot/imported/afterburner.png-95d9a1239ba9614a4ef2d001e06a4092.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/afterburner.png"
|
||||||
|
dest_files=["res://.godot/imported/afterburner.png-95d9a1239ba9614a4ef2d001e06a4092.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
|
||||||
25
assets/icons/extensions_prompts.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"tool": "built-in imagegen",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"id": "afterburner",
|
||||||
|
"path": "assets/icons/afterburner.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi game active ability inventory icon, legible at 42 pixels. Subject: a compact spaceship afterburner module, twin engine boost nozzles with bright blue acceleration trails. Centered in a square, occupying 80% of the canvas. Polished gunmetal and cyan/amber game art, crisp silhouette, consistent three-quarter view, restrained details. Transparent background. No text, UI, border, background, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "shield_charge",
|
||||||
|
"path": "assets/icons/shield_charge.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi game active ability inventory icon, legible at 42 pixels. Subject: an emergency shield recharge capacitor, compact battery bank with a cyan protective hexagonal shield and a small electric arc. Centered in a square, occupying 80% of the canvas. Polished gunmetal and cyan/amber game art, crisp silhouette, consistent three-quarter view, restrained details. Transparent background. No text, UI, border, background, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "repair_drones",
|
||||||
|
"path": "assets/icons/repair_drones.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi game active ability inventory icon, legible at 42 pixels. Subject: two small autonomous spaceship repair drones, articulated manipulator arms, visible welding tool, warm amber welding spark, no hull plating. Centered in a square, occupying 80% of the canvas. Polished gunmetal and cyan/amber game art, crisp silhouette, consistent three-quarter view, restrained details. Transparent background. No text, UI, border, background, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "screwdriver",
|
||||||
|
"path": "assets/icons/screwdriver.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi game salvage action button icon, legible at 16 pixels. Subject: one simple precision screwdriver, amber handle and polished steel shaft, diagonal orientation, bold readable silhouette, no other tools. Centered in a square, occupying 80% of the canvas. Polished gunmetal and cyan/amber game art, crisp silhouette, consistent three-quarter view, restrained details. Transparent background. No text, UI, border, background, watermark or other items."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
assets/icons/repair_drones.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
40
assets/icons/repair_drones.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b1v55dh3vgl78"
|
||||||
|
path="res://.godot/imported/repair_drones.png-1c06bb8551ddc2b1cecc2eee29b821a1.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/repair_drones.png"
|
||||||
|
dest_files=["res://.godot/imported/repair_drones.png-1c06bb8551ddc2b1cecc2eee29b821a1.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
|
||||||
BIN
assets/icons/screwdriver.png
Normal file
|
After Width: | Height: | Size: 759 KiB |
40
assets/icons/screwdriver.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dclr2ixo322yp"
|
||||||
|
path="res://.godot/imported/screwdriver.png-7ce78b723732e8b7321d8be8b4729825.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/screwdriver.png"
|
||||||
|
dest_files=["res://.godot/imported/screwdriver.png-7ce78b723732e8b7321d8be8b4729825.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
|
||||||
BIN
assets/icons/shield_charge.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
40
assets/icons/shield_charge.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bckqak06f6qxc"
|
||||||
|
path="res://.godot/imported/shield_charge.png-de5c7d31ad3e9bddb64f261edd5632cb.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/shield_charge.png"
|
||||||
|
dest_files=["res://.godot/imported/shield_charge.png-de5c7d31ad3e9bddb64f261edd5632cb.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
|
||||||
20
assets/wrecks/prompts.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"tool": "built-in imagegen",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"id": "wreck_frigate",
|
||||||
|
"path": "assets/wrecks/wreck_frigate.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down wreck sprite for a 2D space game. Subject: a broken small space frigate, fractured gunmetal hull, exposed ribs, one torn blue engine nacelle. Single wreck centered in a square, occupying 80% of the canvas. Premium painted realistic sci-fi game art, crisp readable silhouette at 80 pixels, detailed metallic surfaces, neutral upper-left lighting. Transparent background. No text, UI, border, stars, surrounding scenery, outside shadows, explosion or flames."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wreck_freighter",
|
||||||
|
"path": "assets/wrecks/wreck_freighter.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down wreck sprite for a 2D space game. Subject: a destroyed compact cargo spacecraft, crushed angular hull, scattered attached cargo pods, rusted orange panels. Single wreck centered in a square, occupying 80% of the canvas. Premium painted realistic sci-fi game art, crisp readable silhouette at 80 pixels, detailed metallic surfaces, neutral upper-left lighting. Transparent background. No text, UI, border, stars, surrounding scenery, outside shadows, explosion or flames."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wreck_interceptor",
|
||||||
|
"path": "assets/wrecks/wreck_interceptor.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down wreck sprite for a 2D space game. Subject: a ruined sleek interceptor spaceship, snapped wing, burned navy armor, exposed glowing dim cyan wiring. Single wreck centered in a square, occupying 80% of the canvas. Premium painted realistic sci-fi game art, crisp readable silhouette at 80 pixels, detailed metallic surfaces, neutral upper-left lighting. Transparent background. No text, UI, border, stars, surrounding scenery, outside shadows, explosion or flames."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
assets/wrecks/wreck_freighter.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
40
assets/wrecks/wreck_freighter.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cwx1k1akiuhfm"
|
||||||
|
path="res://.godot/imported/wreck_freighter.png-db535807eab479ebfbba43be7cd0e2b2.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/wrecks/wreck_freighter.png"
|
||||||
|
dest_files=["res://.godot/imported/wreck_freighter.png-db535807eab479ebfbba43be7cd0e2b2.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
|
||||||
BIN
assets/wrecks/wreck_frigate.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
40
assets/wrecks/wreck_frigate.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bvj1hdlnec6nj"
|
||||||
|
path="res://.godot/imported/wreck_frigate.png-c70e885156f2b58c93f9f1a465c39b94.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/wrecks/wreck_frigate.png"
|
||||||
|
dest_files=["res://.godot/imported/wreck_frigate.png-c70e885156f2b58c93f9f1a465c39b94.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
|
||||||
BIN
assets/wrecks/wreck_interceptor.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
40
assets/wrecks/wreck_interceptor.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b6hcpbikedl6n"
|
||||||
|
path="res://.godot/imported/wreck_interceptor.png-db737464df7a4040a1be1a610f183903.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/wrecks/wreck_interceptor.png"
|
||||||
|
dest_files=["res://.godot/imported/wreck_interceptor.png-db737464df7a4040a1be1a610f183903.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
|
||||||
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
||||||
[ext_resource type="Script" uid="uid://bpaiuqwsxswii" path="res://scripts/abilities/afterburner_ability.gd" id="2"]
|
[ext_resource type="Script" uid="uid://bpaiuqwsxswii" path="res://scripts/abilities/afterburner_ability.gd" id="2"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" path="res://assets/icons/engine.png" id="icon"]
|
[ext_resource type="Texture2D" path="res://assets/icons/afterburner.png" id="icon"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
||||||
[ext_resource type="Script" uid="uid://bgofku10gduus" path="res://scripts/abilities/repair_drones_ability.gd" id="2"]
|
[ext_resource type="Script" uid="uid://bgofku10gduus" path="res://scripts/abilities/repair_drones_ability.gd" id="2"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" path="res://assets/icons/armor.png" id="icon"]
|
[ext_resource type="Texture2D" path="res://assets/icons/repair_drones.png" id="icon"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1"]
|
||||||
[ext_resource type="Script" uid="uid://bwka1dwxq64sl" path="res://scripts/abilities/shield_charge_ability.gd" id="2"]
|
[ext_resource type="Script" uid="uid://bwka1dwxq64sl" path="res://scripts/abilities/shield_charge_ability.gd" id="2"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" path="res://assets/icons/shield.png" id="icon"]
|
[ext_resource type="Texture2D" path="res://assets/icons/shield_charge.png" id="icon"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
|
|||||||
@ -16,7 +16,7 @@ collision_mask = 5
|
|||||||
script = ExtResource("1_controller")
|
script = ExtResource("1_controller")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
texture_filter = 1
|
texture_filter = 2
|
||||||
|
|
||||||
[node name="ShieldVisual" type="Node2D" parent="."]
|
[node name="ShieldVisual" type="Node2D" parent="."]
|
||||||
z_index = 2
|
z_index = 2
|
||||||
@ -39,3 +39,4 @@ script = ExtResource("5_engine_audio")
|
|||||||
|
|
||||||
[node name="EngineVisual" type="Node2D" parent="."]
|
[node name="EngineVisual" type="Node2D" parent="."]
|
||||||
script = ExtResource("6_engine_visual")
|
script = ExtResource("6_engine_visual")
|
||||||
|
|
||||||
|
|||||||
@ -36,13 +36,13 @@ theme_override_constants/separation = 14
|
|||||||
[node name="Heading" type="Label" parent="Layout"]
|
[node name="Heading" type="Label" parent="Layout"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_colors/font_color = Color(0.92, 0.96, 1, 1)
|
theme_override_colors/font_color = Color(0.92, 0.96, 1, 1)
|
||||||
theme_override_font_sizes/font_size = 34
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "Wybierz statek"
|
text = "HANGAR / WYBÓR STATKU"
|
||||||
|
|
||||||
[node name="Instructions" type="Label" parent="Layout"]
|
[node name="Instructions" type="Label" parent="Layout"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_colors/font_color = Color(0.55, 0.7, 0.82, 1)
|
theme_override_colors/font_color = Color(0.55, 0.7, 0.82, 1)
|
||||||
text = "Kliknij statek, aby od razu rozpocząć grę."
|
text = "Wybierz jednostkę i rozpocznij wyprawę."
|
||||||
|
|
||||||
[node name="ShipScroll" type="ScrollContainer" parent="Layout"]
|
[node name="ShipScroll" type="ScrollContainer" parent="Layout"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
@ -63,7 +63,8 @@ theme_override_constants/separation = 20
|
|||||||
|
|
||||||
[node name="CloseButton" type="Button" parent="Layout/Footer"]
|
[node name="CloseButton" type="Button" parent="Layout/Footer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
custom_minimum_size = Vector2(220, 52)
|
custom_minimum_size = Vector2(180, 40)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_font_sizes/font_size = 20
|
theme_override_font_sizes/font_size = 16
|
||||||
text = "WRÓĆ"
|
text = "‹ WRÓĆ / ESC"
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ extends CanvasLayer
|
|||||||
@onready var inventory_button: Button = $HUDRoot/ShipEquipmentPanel/Contents/InventoryButton
|
@onready var inventory_button: Button = $HUDRoot/ShipEquipmentPanel/Contents/InventoryButton
|
||||||
@onready var inventory_panel: Control = $HUDRoot/ShipInventoryPanel
|
@onready var inventory_panel: Control = $HUDRoot/ShipInventoryPanel
|
||||||
|
|
||||||
var _debug_expanded := true
|
var _debug_expanded := false
|
||||||
var _ability_buttons: Dictionary = {}
|
var _ability_buttons: Dictionary = {}
|
||||||
var _ability_bar: HBoxContainer
|
var _ability_bar: HBoxContainer
|
||||||
var _ability_ready_style: StyleBoxFlat
|
var _ability_ready_style: StyleBoxFlat
|
||||||
@ -14,16 +14,17 @@ var _ability_blocked_style: StyleBoxFlat
|
|||||||
var _inventory_clip: Control
|
var _inventory_clip: Control
|
||||||
var _sidebar: PanelContainer
|
var _sidebar: PanelContainer
|
||||||
var _sidebar_toggle: Button
|
var _sidebar_toggle: Button
|
||||||
var _sidebar_open := true
|
var _sidebar_open := false
|
||||||
var _sidebar_tween: Tween
|
var _sidebar_tween: Tween
|
||||||
const SIDEBAR_WIDTH := 306.0
|
const SIDEBAR_WIDTH := 306.0
|
||||||
|
const EQUIPMENT_UI_SCALE := 0.8
|
||||||
var _debug_scroll: ScrollContainer
|
var _debug_scroll: ScrollContainer
|
||||||
var _captain_panel: PanelContainer
|
var _captain_panel: PanelContainer
|
||||||
var _cockpit: Control
|
var _cockpit: Control
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_sidebar_open = bool(GameState.hud_panel_state.get("ship_open", true))
|
_sidebar_open = bool(GameState.hud_panel_state.get("ship_open", false))
|
||||||
_debug_expanded = bool(GameState.hud_panel_state.get("debug_expanded", true))
|
_debug_expanded = bool(GameState.hud_panel_state.get("debug_expanded", false))
|
||||||
debug_info.visible = _debug_expanded
|
debug_info.visible = _debug_expanded
|
||||||
var energy_indicator := Node2D.new()
|
var energy_indicator := Node2D.new()
|
||||||
energy_indicator.name = "EnergyIndicator"
|
energy_indicator.name = "EnergyIndicator"
|
||||||
@ -48,6 +49,8 @@ func _ready() -> void:
|
|||||||
inventory_panel.set("layout_mode", 0)
|
inventory_panel.set("layout_mode", 0)
|
||||||
inventory_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
inventory_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||||
inventory_panel.size = Vector2(560, inventory_panel.get_combined_minimum_size().y)
|
inventory_panel.size = Vector2(560, inventory_panel.get_combined_minimum_size().y)
|
||||||
|
inventory_panel.scale = Vector2.ONE * EQUIPMENT_UI_SCALE
|
||||||
|
inventory_panel.set("drawer_width", inventory_panel.size.x * EQUIPMENT_UI_SCALE)
|
||||||
$HUDRoot.resized.connect(func() -> void: _layout_sidebar.call_deferred())
|
$HUDRoot.resized.connect(func() -> void: _layout_sidebar.call_deferred())
|
||||||
_create_ability_bar()
|
_create_ability_bar()
|
||||||
debug_toggle.pressed.connect(_toggle_debug)
|
debug_toggle.pressed.connect(_toggle_debug)
|
||||||
@ -120,7 +123,7 @@ func _create_sidebar() -> void:
|
|||||||
_layout_debug()
|
_layout_debug()
|
||||||
|
|
||||||
func _layout_debug() -> void:
|
func _layout_debug() -> void:
|
||||||
if _debug_scroll == null:
|
if not is_instance_valid(_debug_scroll) or not is_instance_valid(_captain_panel):
|
||||||
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)
|
||||||
@ -139,28 +142,31 @@ func _toggle_sidebar() -> void:
|
|||||||
else:
|
else:
|
||||||
close_inventory()
|
close_inventory()
|
||||||
_sidebar_tween = create_tween()
|
_sidebar_tween = create_tween()
|
||||||
_sidebar_tween.tween_property(_sidebar, "position:x", $HUDRoot.size.x - _sidebar.size.x - 8 if _sidebar_open else $HUDRoot.size.x, 0.25).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT if _sidebar_open else Tween.EASE_IN)
|
_sidebar_tween.tween_property(_sidebar, "position:x", $HUDRoot.size.x - _sidebar.size.x * EQUIPMENT_UI_SCALE - 8 if _sidebar_open else $HUDRoot.size.x, 0.25).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT if _sidebar_open else Tween.EASE_IN)
|
||||||
if not _sidebar_open:
|
if not _sidebar_open:
|
||||||
_sidebar_tween.tween_callback(_sidebar.hide)
|
_sidebar_tween.tween_callback(_sidebar.hide)
|
||||||
|
|
||||||
func _layout_sidebar() -> void:
|
func _layout_sidebar() -> void:
|
||||||
|
if not is_instance_valid(_sidebar) or not is_instance_valid(_cockpit):
|
||||||
|
return
|
||||||
if _sidebar_tween != null and _sidebar_tween.is_running():
|
if _sidebar_tween != null and _sidebar_tween.is_running():
|
||||||
_sidebar_tween.kill()
|
_sidebar_tween.kill()
|
||||||
_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)))
|
_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.scale = Vector2.ONE * 0.85
|
||||||
_cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 126)
|
_cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 126)
|
||||||
_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)
|
||||||
_layout_debug()
|
_layout_debug()
|
||||||
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x - 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, 44)
|
||||||
_sidebar.visible = _sidebar_open
|
_sidebar.visible = _sidebar_open
|
||||||
_inventory_clip.size = inventory_panel.size
|
_inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE
|
||||||
_layout_inventory()
|
_layout_inventory()
|
||||||
|
|
||||||
func _layout_inventory() -> void:
|
func _layout_inventory() -> void:
|
||||||
if _inventory_clip == null:
|
if not is_instance_valid(_inventory_clip) or not is_instance_valid(_sidebar):
|
||||||
return
|
return
|
||||||
var equipment := _sidebar.get_node("Scroll/Contents/ShipEquipmentPanel") as Control
|
var equipment := _sidebar.get_node("Scroll/Contents/ShipEquipmentPanel") as Control
|
||||||
_inventory_clip.position = Vector2(maxf(12.0, _sidebar.position.x - _inventory_clip.size.x - 8), minf(equipment.global_position.y, maxf(8.0, $HUDRoot.size.y - inventory_panel.size.y - 8)))
|
_inventory_clip.position = Vector2(maxf(12.0, _sidebar.position.x - _inventory_clip.size.x - 8), minf(equipment.global_position.y, maxf(8.0, $HUDRoot.size.y - inventory_panel.size.y * EQUIPMENT_UI_SCALE - 8)))
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
_layout_inventory()
|
_layout_inventory()
|
||||||
@ -249,17 +255,30 @@ func _create_ability_bar() -> void:
|
|||||||
panel.name = "ActiveAbilities"
|
panel.name = "ActiveAbilities"
|
||||||
$HUDRoot.add_child(panel)
|
$HUDRoot.add_child(panel)
|
||||||
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
|
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
|
||||||
panel.offset_left = -300.0
|
panel.offset_left = -120.0
|
||||||
panel.offset_right = 300.0
|
panel.offset_right = 120.0
|
||||||
panel.offset_top = -188.0
|
panel.offset_top = -176.0
|
||||||
panel.offset_bottom = -146.0
|
panel.offset_bottom = -132.0
|
||||||
|
panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
||||||
_ability_bar = HBoxContainer.new()
|
_ability_bar = HBoxContainer.new()
|
||||||
|
_ability_bar.name = "AbilityButtons"
|
||||||
|
_ability_bar.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
_ability_bar.add_theme_constant_override("separation", 4)
|
_ability_bar.add_theme_constant_override("separation", 4)
|
||||||
panel.add_child(_ability_bar)
|
panel.add_child(_ability_bar)
|
||||||
for index in ShipInventory.EXTENSION_SLOT_COUNT:
|
for index in ShipInventory.EXTENSION_SLOT_COUNT:
|
||||||
var button := Button.new()
|
var button := Button.new()
|
||||||
button.name = "Ability%d" % (index + 1)
|
button.name = "Ability%d" % (index + 1)
|
||||||
button.custom_minimum_size = Vector2(110, 36)
|
button.custom_minimum_size = Vector2(44, 44)
|
||||||
|
button.expand_icon = true
|
||||||
|
button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
button.add_theme_constant_override("icon_max_width", 30)
|
||||||
|
button.focus_mode = Control.FOCUS_NONE
|
||||||
|
var shortcut := Label.new()
|
||||||
|
shortcut.text = str(index + 1)
|
||||||
|
shortcut.position = Vector2(3, 1)
|
||||||
|
shortcut.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
shortcut.add_theme_font_size_override("font_size", 9)
|
||||||
|
button.add_child(shortcut)
|
||||||
button.add_theme_font_size_override("font_size", 11)
|
button.add_theme_font_size_override("font_size", 11)
|
||||||
button.pressed.connect(func() -> void: player.call("activate_ability", index))
|
button.pressed.connect(func() -> void: player.call("activate_ability", index))
|
||||||
_ability_bar.add_child(button)
|
_ability_bar.add_child(button)
|
||||||
@ -277,14 +296,17 @@ func _update_ability_bar() -> void:
|
|||||||
any_equipped = true
|
any_equipped = true
|
||||||
var reason: String = player.call("ability_unavailable_reason", index)
|
var reason: String = player.call("ability_unavailable_reason", index)
|
||||||
button.disabled = not reason.is_empty()
|
button.disabled = not reason.is_empty()
|
||||||
button.text = "[%d] %s\n%s" % [index + 1, ability.display_name, "GOTOWE" if reason.is_empty() else reason]
|
var item: ItemInstance = player.get_node("ShipInventory").get_item("extension", index)
|
||||||
|
button.icon = item.definition.icon
|
||||||
|
button.text = ""
|
||||||
|
button.add_theme_color_override("icon_disabled_color", Color(0.45, 0.5, 0.55, 0.65))
|
||||||
var style := _ability_ready_style if reason.is_empty() else _ability_blocked_style
|
var style := _ability_ready_style if reason.is_empty() else _ability_blocked_style
|
||||||
button.add_theme_stylebox_override("normal", style)
|
button.add_theme_stylebox_override("normal", style)
|
||||||
button.add_theme_stylebox_override("disabled", style)
|
button.add_theme_stylebox_override("disabled", style)
|
||||||
button.add_theme_stylebox_override("hover", style)
|
button.add_theme_stylebox_override("hover", style)
|
||||||
button.add_theme_color_override("font_color", Color("a5ffda"))
|
button.add_theme_color_override("font_color", Color("a5ffda"))
|
||||||
button.add_theme_color_override("font_disabled_color", Color("a3aebb"))
|
button.add_theme_color_override("font_disabled_color", Color("a3aebb"))
|
||||||
button.tooltip_text = ability.description + ("\n" + reason if not reason.is_empty() else "\nGotowe")
|
button.tooltip_text = "[%d] %s\n" % [index + 1, ability.display_name] + ability.description + ("\n" + reason if not reason.is_empty() else "\nGotowe")
|
||||||
_ability_bar.get_parent().visible = any_equipped
|
_ability_bar.get_parent().visible = any_equipped
|
||||||
|
|
||||||
func _make_ability_style(ready: bool) -> StyleBoxFlat:
|
func _make_ability_style(ready: bool) -> StyleBoxFlat:
|
||||||
|
|||||||
28
scripts/game/laser_beam_visual.gd
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
extends Line2D
|
||||||
|
|
||||||
|
var _time := 0.0
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
# Draw the beam in layers instead of a flat line. No bloom is required.
|
||||||
|
default_color = Color.TRANSPARENT
|
||||||
|
width = 0.0
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
_time += delta
|
||||||
|
if visible:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if points.size() < 2:
|
||||||
|
return
|
||||||
|
var start := points[0]
|
||||||
|
var end := points[1]
|
||||||
|
var pulse := 0.88 + sin(_time * 65.0) * 0.12
|
||||||
|
draw_line(start, end, Color(0.1, 0.65, 1.0, 0.09 * pulse), 16, true)
|
||||||
|
draw_line(start, end, Color(0.15, 0.8, 1.0, 0.2 * pulse), 9, true)
|
||||||
|
draw_line(start, end, Color(0.3, 0.92, 1.0, 0.7), 3.8, true)
|
||||||
|
draw_line(start, end, Color(0.9, 1.0, 1.0, 0.96), 1.4, true)
|
||||||
|
for point in [start, end]:
|
||||||
|
draw_circle(point, 9 * pulse, Color(0.1, 0.8, 1.0, 0.12))
|
||||||
|
draw_circle(point, 4 * pulse, Color(0.35, 0.95, 1.0, 0.6))
|
||||||
|
draw_circle(point, 1.8, Color(0.9, 1.0, 1.0))
|
||||||
1
scripts/game/laser_beam_visual.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://g1ikmcnodycw
|
||||||
21
scripts/game/muzzle_flash.gd
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
var _age := 0.0
|
||||||
|
const DURATION := 0.075
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
z_index = 25
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
_age += delta
|
||||||
|
if _age >= DURATION:
|
||||||
|
queue_free()
|
||||||
|
else:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
var fade := 1.0 - _age / DURATION
|
||||||
|
draw_circle(Vector2.ZERO, 12 * fade, Color(1.0, 0.48, 0.08, 0.18 * fade))
|
||||||
|
draw_colored_polygon(PackedVector2Array([Vector2(-2, -3), Vector2(8, -2), Vector2(19, 0), Vector2(8, 2), Vector2(-2, 3)]), Color(1.0, 0.7, 0.18, fade))
|
||||||
|
draw_line(Vector2(-2, 0), Vector2(13 * fade, 0), Color(1.0, 0.97, 0.8, fade), 2, true)
|
||||||
|
draw_line(Vector2(1, -7 * fade), Vector2(1, 7 * fade), Color(1.0, 0.78, 0.3, fade * 0.7), 1, true)
|
||||||
1
scripts/game/muzzle_flash.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://b56icy0o06n6k
|
||||||
@ -3,18 +3,18 @@ class_name ShipCatalog
|
|||||||
|
|
||||||
# Base hull values, before equipment and captain bonuses.
|
# Base hull values, before equipment and captain bonuses.
|
||||||
const SHIPS := [
|
const SHIPS := [
|
||||||
{"number": 0, "name": "Aegis", "role": "Wzmocnione tarcze", "hull": 100.0, "shields": 125.0, "energy": 100.0, "speed": 90.0},
|
{"number": 0, "name": "Szerszeń", "asset": "szerszen", "role": "MYŚLIWIEC • SZYBKOŚĆ", "accent": Color("efb866"), "hull": 100.0, "shields": 100.0, "energy": 100.0, "speed": 108.0},
|
||||||
{"number": 2, "name": "Titan", "role": "Wzmocniony kadłub", "hull": 125.0, "shields": 100.0, "energy": 100.0, "speed": 90.0},
|
{"number": 2, "name": "Bastion", "asset": "bastion", "role": "FREGATA • PANCERZ", "accent": Color("de976b"), "hull": 125.0, "shields": 100.0, "energy": 100.0, "speed": 90.0},
|
||||||
{"number": 3, "name": "Eagle", "role": "Szybki myśliwiec", "hull": 100.0, "shields": 100.0, "energy": 100.0, "speed": 108.0},
|
{"number": 3, "name": "Wędrowiec", "asset": "wedrowiec", "role": "ZWIADEK • TARCZE", "accent": Color("64d8ed"), "hull": 100.0, "shields": 125.0, "energy": 100.0, "speed": 90.0},
|
||||||
{"number": 7, "name": "Phantom", "role": "Większy zapas energii", "hull": 100.0, "shields": 100.0, "energy": 125.0, "speed": 90.0},
|
{"number": 7, "name": "Żmija", "asset": "zmija", "role": "KORSARZ • ENERGIA", "accent": Color("b796ff"), "hull": 100.0, "shields": 100.0, "energy": 125.0, "speed": 90.0},
|
||||||
]
|
]
|
||||||
|
|
||||||
static func texture_path(ship: Dictionary) -> String:
|
static func texture_path(ship: Dictionary) -> String:
|
||||||
return "res://assets/Ships/Spaceship_%d.png" % int(ship["number"])
|
return "res://assets/Ships/player/%s.png" % ship["asset"]
|
||||||
|
|
||||||
static func for_path(path: String) -> Dictionary:
|
static func for_path(path: String) -> Dictionary:
|
||||||
for ship in SHIPS:
|
for ship in SHIPS:
|
||||||
if texture_path(ship) == path:
|
if texture_path(ship) == path or path == "res://assets/Ships/Spaceship_%d.png" % int(ship["number"]):
|
||||||
return ship
|
return ship
|
||||||
return SHIPS[0]
|
return SHIPS[0]
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ func _ready() -> void:
|
|||||||
_ensure_input_action(&"ship_fire_missile", MOUSE_BUTTON_MIDDLE)
|
_ensure_input_action(&"ship_fire_missile", MOUSE_BUTTON_MIDDLE)
|
||||||
for slot_index in ShipInventory.WEAPON_SLOT_COUNT:
|
for slot_index in ShipInventory.WEAPON_SLOT_COUNT:
|
||||||
var beam := Line2D.new()
|
var beam := Line2D.new()
|
||||||
|
beam.set_script(preload("res://scripts/game/laser_beam_visual.gd"))
|
||||||
beam.width = 4.0
|
beam.width = 4.0
|
||||||
beam.default_color = Color(0.35, 0.9, 1.0, 0.92)
|
beam.default_color = Color(0.35, 0.9, 1.0, 0.92)
|
||||||
beam.z_index = 20
|
beam.z_index = 20
|
||||||
@ -148,6 +149,18 @@ func _fire_projectile(item: ItemInstance) -> void:
|
|||||||
ship.get_parent().add_child(projectile)
|
ship.get_parent().add_child(projectile)
|
||||||
projectile.set("missile_homing", definition.missile_homing)
|
projectile.set("missile_homing", definition.missile_homing)
|
||||||
WEAPON_AUDIO_SCRIPT.play(ship.get_parent(), muzzle_position, definition.weapon_kind)
|
WEAPON_AUDIO_SCRIPT.play(ship.get_parent(), muzzle_position, definition.weapon_kind)
|
||||||
|
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||||
|
var flash := Node2D.new()
|
||||||
|
flash.set_script(preload("res://scripts/game/muzzle_flash.gd"))
|
||||||
|
# Keep the short flash attached to the muzzle while the ship moves.
|
||||||
|
ship.add_child(flash)
|
||||||
|
flash.global_position = muzzle_position
|
||||||
|
flash.global_rotation = direction.angle()
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
for beam in _laser_lines:
|
||||||
|
if is_instance_valid(beam):
|
||||||
|
beam.queue_free()
|
||||||
|
|
||||||
func _fire_laser(slot_index: int, item: ItemInstance) -> void:
|
func _fire_laser(slot_index: int, item: ItemInstance) -> void:
|
||||||
var definition := item.definition
|
var definition := item.definition
|
||||||
|
|||||||
@ -177,7 +177,19 @@ func _draw() -> void:
|
|||||||
draw_texture_rect(PLASMA_TEXTURE, Rect2(-texture_size * 0.5, texture_size), false)
|
draw_texture_rect(PLASMA_TEXTURE, Rect2(-texture_size * 0.5, texture_size), false)
|
||||||
draw_set_transform(Vector2.ZERO)
|
draw_set_transform(Vector2.ZERO)
|
||||||
ItemDefinition.WeaponKind.MACHINE_GUN:
|
ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||||
draw_rect(Rect2(-7.0, -2.0, 14.0, 4.0), Color(1.0, 0.82, 0.38, 1.0))
|
# Tapered tracer, warm halo and a bright metallic projectile core.
|
||||||
|
for index in 6:
|
||||||
|
var tail_distance := 5.0 + index * 4.0
|
||||||
|
if tail_distance >= _distance_travelled:
|
||||||
|
break
|
||||||
|
var fade := 1.0 - float(index) / 6.0
|
||||||
|
var tip := Vector2(-tail_distance, 0)
|
||||||
|
var tail := Vector2(-minf(tail_distance + 4.0, _distance_travelled), 0)
|
||||||
|
draw_line(tail, tip, Color(1.0, 0.48, 0.1, fade * 0.55), 1.8 * fade, true)
|
||||||
|
draw_line(Vector2(-9, 0), Vector2(6, 0), Color(1.0, 0.56, 0.12, 0.18), 7, true)
|
||||||
|
draw_line(Vector2(-7, 0), Vector2(6, 0), Color(1.0, 0.8, 0.3), 2.5, true)
|
||||||
|
draw_line(Vector2(-3, 0), Vector2(7, 0), Color(1.0, 0.98, 0.84), 1.2, true)
|
||||||
|
draw_circle(Vector2(6, 0), 1.5, Color(1.0, 0.94, 0.65))
|
||||||
ItemDefinition.WeaponKind.MISSILE:
|
ItemDefinition.WeaponKind.MISSILE:
|
||||||
_draw_missile()
|
_draw_missile()
|
||||||
|
|
||||||
|
|||||||
@ -298,26 +298,39 @@ func _comparison_stats(bonuses: Dictionary) -> Dictionary:
|
|||||||
stats[data[0]] = {"value": value, "name": data[3], "unit": data[4]}
|
stats[data[0]] = {"value": value, "name": data[3], "unit": data[4]}
|
||||||
for data in [["max_energy", "base_max_energy", "Energia", "pkt"], ["scanner_range", "base_scanner_range", "Zasięg skanera", "px"], ["energy_regeneration", "base_energy_regeneration", "Regeneracja energii", "pkt/s"], ["shield_regeneration", "base_shield_regeneration", "Regeneracja tarcz", "pkt/s"]]:
|
for data in [["max_energy", "base_max_energy", "Energia", "pkt"], ["scanner_range", "base_scanner_range", "Zasięg skanera", "px"], ["energy_regeneration", "base_energy_regeneration", "Regeneracja energii", "pkt/s"], ["shield_regeneration", "base_shield_regeneration", "Regeneracja tarcz", "pkt/s"]]:
|
||||||
stats[data[0]] = {"value": float(ship.get(data[1])) + float(bonuses.get(data[0], 0.0)), "name": data[2], "unit": data[3]}
|
stats[data[0]] = {"value": float(ship.get(data[1])) + float(bonuses.get(data[0], 0.0)), "name": data[2], "unit": data[3]}
|
||||||
var captain_damage := 1.0 + GameState.captain.get_skill_bonus("gunner")
|
# These stats are bonuses in their own right, not rewards or hit scenarios.
|
||||||
var damage_factor := (1.0 + float(bonuses.get("damage_percent", 0.0)) / 100.0) * captain_damage
|
for data in [["damage_percent", "Obrażenia broni"], ["critical_damage_percent", "Obrażenia krytyczne"], ["critical_chance_percent", "Szansa na krytyk"], ["shield_on_damage_percent", "Odzysk tarcz z obrażeń"], ["experience_percent", "Doświadczenie"], ["credits_percent", "Kredyty"]]:
|
||||||
var critical_factor := preload("res://scripts/captain/captain_balance.gd").BASE_CRITICAL_MULTIPLIER * (1.0 + maxf(0.0, float(bonuses.get("critical_damage_percent", 0.0)) / 100.0))
|
stats[data[0]] = {"value": float(bonuses.get(data[0], 0.0)), "name": data[1], "unit": "%"}
|
||||||
for index in weapon_slots.size():
|
stats["missile_cooldown_reduction"] = {"value": float(bonuses.get("missile_cooldown_reduction", 0.0)), "name": "Skrócenie cooldownu rakiet", "unit": "s"}
|
||||||
var weapon := weapon_slots[index]
|
|
||||||
if weapon == null:
|
|
||||||
continue
|
|
||||||
var damage := weapon.get_stat_total("damage") * damage_factor
|
|
||||||
var binding: String = ["LPM", "PPM", "ŚPM"][index]
|
|
||||||
stats["weapon_damage_%d" % index] = {"value": damage, "name": "Śr. obrażenia [%s]" % binding, "unit": "DMG"}
|
|
||||||
stats["weapon_critical_%d" % index] = {"value": damage * critical_factor, "name": "Śr. krytyk [%s]" % binding, "unit": "DMG"}
|
|
||||||
if weapon.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
|
||||||
stats["missile_cooldown_%d" % index] = {"value": -maxf(1.0, 5.0 - float(bonuses.get("missile_cooldown_reduction", 0.0))), "name": "Skrócenie cooldownu [%s]" % binding, "unit": "s"}
|
|
||||||
var chance := clampf(GameState.captain.get_skill_bonus("sharp_eye") + float(bonuses.get("critical_chance_percent", 0.0)) / 100.0, 0.0, 1.0)
|
|
||||||
stats["critical_chance"] = {"value": chance * 100.0, "name": "Krytyki na 100 strzałów", "unit": "trafień"}
|
|
||||||
stats["shield_recovery"] = {"value": maxf(0.0, float(bonuses.get("shield_on_damage_percent", 0.0))), "name": "Odzysk tarcz na 100 DMG", "unit": "pkt"}
|
|
||||||
var balance := preload("res://scripts/captain/captain_balance.gd")
|
|
||||||
var scale_factor := 1.0 + 0.05 * (clampi(GameState.system_level, 1, 1000) - 1)
|
|
||||||
for tier in 3:
|
|
||||||
var caption: String = ["wróg", "elita", "boss"][tier]
|
|
||||||
stats["xp_%d" % tier] = {"value": roundi(balance.KILL_XP[tier] * scale_factor * maxf(0.0, 1.0 + float(bonuses.get("experience_percent", 0.0)) / 100.0)), "name": "EXP / %s" % caption, "unit": "EXP"}
|
|
||||||
stats["credits_%d" % tier] = {"value": roundi(balance.KILL_CREDITS[tier] * scale_factor * maxf(0.0, 1.0 + float(bonuses.get("credits_percent", 0.0)) / 100.0)), "name": "Kredyty / %s" % caption, "unit": "kr"}
|
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
func get_weapon_comparison(item: ItemInstance, slot_index: int) -> Dictionary:
|
||||||
|
if item == null or item.definition == null or item.definition.category != ItemDefinition.Category.WEAPON or slot_index < 0 or slot_index >= weapon_slots.size():
|
||||||
|
return {}
|
||||||
|
var equipped := weapon_slots[slot_index]
|
||||||
|
var before := _comparison_bonuses()
|
||||||
|
var after := _comparison_bonuses(item, equipped)
|
||||||
|
var rows := get_item_comparison(item, equipped)
|
||||||
|
var flat_damage := _weapon_flat_damage_addons(item) - _weapon_flat_damage_addons(equipped)
|
||||||
|
if not is_zero_approx(flat_damage):
|
||||||
|
rows.append({"key": "flat_damage_addon", "name": "Obrażenia z addonów", "delta": flat_damage, "unit": "DMG"})
|
||||||
|
return {"slot": slot_index, "dps_delta": _weapon_dps(item, after) - _weapon_dps(equipped, before), "stats": rows}
|
||||||
|
|
||||||
|
func _weapon_flat_damage_addons(item: ItemInstance) -> float:
|
||||||
|
var total := 0.0
|
||||||
|
if item != null:
|
||||||
|
for modifier in item.additional_modifiers:
|
||||||
|
if modifier != null and modifier.stat_key == "damage":
|
||||||
|
total += modifier.value
|
||||||
|
return total
|
||||||
|
|
||||||
|
func _weapon_dps(item: ItemInstance, bonuses: Dictionary) -> float:
|
||||||
|
if item == null or item.definition == null:
|
||||||
|
return 0.0
|
||||||
|
var damage_factor := (1.0 + float(bonuses.get("damage_percent", 0.0)) / 100.0) * (1.0 + GameState.captain.get_skill_bonus("gunner"))
|
||||||
|
var chance := clampf(GameState.captain.get_skill_bonus("sharp_eye") + float(bonuses.get("critical_chance_percent", 0.0)) / 100.0, 0.0, 1.0)
|
||||||
|
var critical_factor := preload("res://scripts/captain/captain_balance.gd").BASE_CRITICAL_MULTIPLIER * (1.0 + maxf(0.0, float(bonuses.get("critical_damage_percent", 0.0)) / 100.0))
|
||||||
|
var interval := item.definition.fire_interval
|
||||||
|
if item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||||
|
interval = maxf(1.0, 5.0 - float(bonuses.get("missile_cooldown_reduction", 0.0)))
|
||||||
|
return item.get_stat_total("damage") * damage_factor * (1.0 + chance * (critical_factor - 1.0)) / maxf(0.001, interval)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ extends StaticBody2D
|
|||||||
|
|
||||||
const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
||||||
const ASTEROID_TEXTURES := [preload("res://assets/asteroids/asteroid_rock.png"), preload("res://assets/asteroids/asteroid_metal.png"), preload("res://assets/asteroids/asteroid_ice.png")]
|
const ASTEROID_TEXTURES := [preload("res://assets/asteroids/asteroid_rock.png"), preload("res://assets/asteroids/asteroid_metal.png"), preload("res://assets/asteroids/asteroid_ice.png")]
|
||||||
|
const WRECK_TEXTURES := [preload("res://assets/wrecks/wreck_frigate.png"), preload("res://assets/wrecks/wreck_freighter.png"), preload("res://assets/wrecks/wreck_interceptor.png")]
|
||||||
const LOOT := preload("res://scripts/items/loot_pickup.gd")
|
const LOOT := preload("res://scripts/items/loot_pickup.gd")
|
||||||
var kind := "wreck"
|
var kind := "wreck"
|
||||||
var poi_id := ""
|
var poi_id := ""
|
||||||
@ -41,6 +42,14 @@ func _ready() -> void:
|
|||||||
_asteroid_sprite.rotation = deg_to_rad(posmod(reward_seed, 360))
|
_asteroid_sprite.rotation = deg_to_rad(posmod(reward_seed, 360))
|
||||||
_asteroid_spin = (0.025 + posmod(reward_seed, 12) * 0.005) * (1.0 if reward_seed % 2 == 0 else -1.0)
|
_asteroid_spin = (0.025 + posmod(reward_seed, 12) * 0.005) * (1.0 if reward_seed % 2 == 0 else -1.0)
|
||||||
add_child(_asteroid_sprite)
|
add_child(_asteroid_sprite)
|
||||||
|
if kind == "wreck":
|
||||||
|
var sprite := Sprite2D.new()
|
||||||
|
sprite.name = "WreckSprite"
|
||||||
|
sprite.texture = WRECK_TEXTURES[posmod(reward_seed, WRECK_TEXTURES.size())]
|
||||||
|
var texture_size := sprite.texture.get_size()
|
||||||
|
sprite.scale = Vector2.ONE * (92.0 / maxf(texture_size.x, texture_size.y))
|
||||||
|
sprite.rotation = deg_to_rad(posmod(reward_seed, 360))
|
||||||
|
add_child(sprite)
|
||||||
_label = Label.new()
|
_label = Label.new()
|
||||||
_label.light_mask = 4
|
_label.light_mask = 4
|
||||||
_label.position = Vector2(-160, 40)
|
_label.position = Vector2(-160, 40)
|
||||||
@ -66,12 +75,6 @@ func _process(delta: float) -> void:
|
|||||||
func reward_scale() -> float:
|
func reward_scale() -> float:
|
||||||
return 1.0 + 0.05 * (clampi(GameState.system_level, 1, 1000) - 1)
|
return 1.0 + 0.05 * (clampi(GameState.system_level, 1, 1000) - 1)
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
if kind == "wreck":
|
|
||||||
draw_colored_polygon(PackedVector2Array([Vector2(-38, 20), Vector2(-16, -30), Vector2(7, -12), Vector2(22, 27), Vector2(-5, 14)]), Color("626b78"))
|
|
||||||
draw_line(Vector2(-12, -20), Vector2(4, 15), Color("df9c67"), 3, true)
|
|
||||||
draw_colored_polygon(PackedVector2Array([Vector2(28, -16), Vector2(42, -5), Vector2(29, 8)]), Color("434e60"))
|
|
||||||
|
|
||||||
func _update_label(near: bool) -> void:
|
func _update_label(near: bool) -> void:
|
||||||
if kind == "ruin":
|
if kind == "ruin":
|
||||||
_label.text = "?"
|
_label.text = "?"
|
||||||
|
|||||||
@ -55,7 +55,7 @@ func _ready() -> void:
|
|||||||
_captain.changed.connect(_refresh)
|
_captain.changed.connect(_refresh)
|
||||||
player.get_node("ShipInventory").connect("inventory_changed", _refresh)
|
player.get_node("ShipInventory").connect("inventory_changed", _refresh)
|
||||||
_refresh()
|
_refresh()
|
||||||
if bool(GameState.hud_panel_state.get("captain_collapsed", false)):
|
if bool(GameState.hud_panel_state.get("captain_collapsed", true)):
|
||||||
_toggle_collapsed()
|
_toggle_collapsed()
|
||||||
|
|
||||||
func _train(skill: String) -> void:
|
func _train(skill: String) -> void:
|
||||||
|
|||||||
@ -13,23 +13,34 @@ var _delete_button: Button
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if slot_kind == "cargo":
|
if slot_kind == "cargo":
|
||||||
var overlay := Control.new()
|
var overlay := Control.new()
|
||||||
|
overlay.name = "ActionOverlay"
|
||||||
overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
overlay.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
add_child(overlay)
|
add_child(overlay)
|
||||||
_delete_button = Button.new()
|
_delete_button = Button.new()
|
||||||
_delete_button.text = "x"
|
_delete_button.name = "SalvageButton"
|
||||||
|
_delete_button.icon = preload("res://assets/icons/screwdriver.png")
|
||||||
|
_delete_button.expand_icon = true
|
||||||
|
_delete_button.add_theme_constant_override("icon_max_width", 18)
|
||||||
_delete_button.z_index = 5
|
_delete_button.z_index = 5
|
||||||
_delete_button.tooltip_text = "Rozłóż przedmiot: +10 części"
|
_delete_button.tooltip_text = "Rozłóż przedmiot: +10 części"
|
||||||
_delete_button.flat = true
|
_delete_button.focus_mode = Control.FOCUS_NONE
|
||||||
_delete_button.add_theme_font_size_override("font_size", 13)
|
var tool_style := StyleBoxFlat.new()
|
||||||
_delete_button.add_theme_color_override("font_color", Color("ff8989"))
|
tool_style.bg_color = Color(0.04, 0.07, 0.1, 0.96)
|
||||||
|
tool_style.border_color = Color("b68c53")
|
||||||
|
tool_style.set_border_width_all(1)
|
||||||
|
tool_style.set_corner_radius_all(3)
|
||||||
|
tool_style.set_content_margin_all(2)
|
||||||
|
_delete_button.add_theme_stylebox_override("normal", tool_style)
|
||||||
|
_delete_button.add_theme_stylebox_override("hover", tool_style)
|
||||||
|
_delete_button.add_theme_stylebox_override("pressed", tool_style)
|
||||||
overlay.add_child(_delete_button)
|
overlay.add_child(_delete_button)
|
||||||
_delete_button.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
_delete_button.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
||||||
# Overlay follows the panel's content rect (5 px top, 18 px right padding).
|
_delete_button.offset_left = -24
|
||||||
_delete_button.offset_left = -4
|
_delete_button.offset_right = -2
|
||||||
_delete_button.offset_right = 16
|
_delete_button.offset_top = 2
|
||||||
_delete_button.offset_top = -3
|
_delete_button.offset_bottom = 24
|
||||||
_delete_button.offset_bottom = 17
|
_delete_button.custom_minimum_size = Vector2(22, 22)
|
||||||
_delete_button.custom_minimum_size = Vector2(20, 20)
|
_delete_button.hide()
|
||||||
_delete_button.pressed.connect(_delete_item)
|
_delete_button.pressed.connect(_delete_item)
|
||||||
_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:
|
||||||
@ -59,9 +70,17 @@ func _ready() -> void:
|
|||||||
_refresh()
|
_refresh()
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
|
_update_salvage_visibility()
|
||||||
if slot_kind == "weapon" and _has_missile():
|
if slot_kind == "weapon" and _has_missile():
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
func _update_salvage_visibility() -> void:
|
||||||
|
if _delete_button == null or _inventory == null:
|
||||||
|
return
|
||||||
|
var hovered_control := get_viewport().gui_get_hovered_control()
|
||||||
|
var hovered := hovered_control == self or (hovered_control != null and is_ancestor_of(hovered_control))
|
||||||
|
_delete_button.visible = is_visible_in_tree() and hovered and _inventory.get_item(slot_kind, slot_index) != null and not get_viewport().gui_is_dragging()
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
if slot_kind != "weapon" or not _has_missile() or _inventory == null:
|
if slot_kind != "weapon" or not _has_missile() or _inventory == null:
|
||||||
return
|
return
|
||||||
@ -83,8 +102,7 @@ func _refresh() -> void:
|
|||||||
tooltip_text = item.get_tooltip_text() if item != null else _empty_slot_text()
|
tooltip_text = item.get_tooltip_text() if item != null else _empty_slot_text()
|
||||||
if item != null and slot_kind == "weapon" and _has_missile():
|
if item != null and slot_kind == "weapon" and _has_missile():
|
||||||
tooltip_text += "\nCooldown po addonach: %.2f s\nZapas rakiet: %d" % [_inventory.get_missile_cooldown(item), _inventory.get_missile_count()]
|
tooltip_text += "\nCooldown po addonach: %.2f s\nZapas rakiet: %d" % [_inventory.get_missile_cooldown(item), _inventory.get_missile_count()]
|
||||||
if _delete_button:
|
_update_salvage_visibility()
|
||||||
_delete_button.visible = item != null
|
|
||||||
if item == null or item.definition == null:
|
if item == null or item.definition == null:
|
||||||
slot_label.add_theme_color_override("font_color", Color("82909e"))
|
slot_label.add_theme_color_override("font_color", Color("82909e"))
|
||||||
slot_label.text = "—"
|
slot_label.text = "—"
|
||||||
@ -155,6 +173,9 @@ func _make_custom_tooltip(for_text: String) -> Object:
|
|||||||
return panel
|
return panel
|
||||||
|
|
||||||
func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||||
|
if item.definition.category == ItemDefinition.Category.WEAPON:
|
||||||
|
_add_weapon_comparison(columns, item)
|
||||||
|
return
|
||||||
var module_index := ShipInventory.MODULE_CATEGORIES.find(item.definition.category)
|
var module_index := ShipInventory.MODULE_CATEGORIES.find(item.definition.category)
|
||||||
if module_index < 0:
|
if module_index < 0:
|
||||||
return
|
return
|
||||||
@ -184,6 +205,63 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
|||||||
comparison.pop()
|
comparison.pop()
|
||||||
comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.")
|
comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.")
|
||||||
|
|
||||||
|
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_color_override("font_color", color)
|
||||||
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
return label
|
||||||
|
|
||||||
|
func _comparison_delta(value: float) -> Label:
|
||||||
|
var label := _comparison_label(("%+.2f" % value).replace(".", ",") if not is_zero_approx(value) else "—", 64, Color("79e6a0") if value > 0.0 else (Color("ff8989") if value < 0.0 else Color("82909e")))
|
||||||
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||||
|
return label
|
||||||
|
|
||||||
|
func _add_weapon_comparison(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||||
|
columns.add_child(VSeparator.new())
|
||||||
|
var section := VBoxContainer.new()
|
||||||
|
section.name = "WeaponComparison"
|
||||||
|
section.add_theme_constant_override("separation", 6)
|
||||||
|
columns.add_child(section)
|
||||||
|
section.add_child(_comparison_label("ZMIANY PO WYMIANIE BRONI", 0, Color("91dbea")))
|
||||||
|
var grid := GridContainer.new()
|
||||||
|
grid.columns = 4
|
||||||
|
grid.add_theme_constant_override("h_separation", 8)
|
||||||
|
grid.add_theme_constant_override("v_separation", 4)
|
||||||
|
section.add_child(grid)
|
||||||
|
grid.add_child(_comparison_label("", 185))
|
||||||
|
var comparisons: Array[Dictionary] = []
|
||||||
|
for index in [0, 2, 1]:
|
||||||
|
grid.add_child(_comparison_label("%d · %s" % [index + 1, ["LPM", "PPM", "ŚPM"][index]], 64, Color("91dbea")))
|
||||||
|
comparisons.append(_inventory.get_weapon_comparison(item, index))
|
||||||
|
grid.add_child(_comparison_label("DPS broni", 185, Color("ffd166")))
|
||||||
|
for comparison in comparisons:
|
||||||
|
grid.add_child(_comparison_delta(comparison["dps_delta"]))
|
||||||
|
var keys := {}
|
||||||
|
for comparison in comparisons:
|
||||||
|
for row in comparison["stats"]:
|
||||||
|
keys[row["key"]] = row
|
||||||
|
for key in keys:
|
||||||
|
var row: Dictionary = keys[key]
|
||||||
|
var compact_name: String = {"missile_cooldown_reduction": "Skróc. cooldownu rakiet", "critical_damage_percent": "Obraż. krytyczne", "energy_regeneration": "Regener. energii", "shield_regeneration": "Regener. tarcz", "shield_on_damage_percent": "Odzysk tarcz z obr."}.get(key, row["name"])
|
||||||
|
var caption: Label = _comparison_label("%s (%s)" % [compact_name, row["unit"]], 185)
|
||||||
|
caption.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
caption.custom_minimum_size.x = 185
|
||||||
|
caption.size_flags_horizontal = Control.SIZE_FILL
|
||||||
|
grid.add_child(caption)
|
||||||
|
for comparison in comparisons:
|
||||||
|
var delta := 0.0
|
||||||
|
for change in comparison["stats"]:
|
||||||
|
if change["key"] == key:
|
||||||
|
delta = float(change["delta"])
|
||||||
|
break
|
||||||
|
grid.add_child(_comparison_delta(delta))
|
||||||
|
var note := _comparison_label("Średni DPS z krytykami i cooldownem.\nBez ograniczeń energii i amunicji.\nAddony uwzględniają zdjęcie obecnej broni.", 0, Color("a0b2c4"))
|
||||||
|
note.add_theme_font_size_override("font_size", 10)
|
||||||
|
section.add_child(note)
|
||||||
|
|
||||||
func _get_drag_data(_at_position: Vector2) -> Variant:
|
func _get_drag_data(_at_position: Vector2) -> Variant:
|
||||||
if not _inventory:
|
if not _inventory:
|
||||||
return null
|
return null
|
||||||
|
|||||||
@ -40,7 +40,7 @@ func _layout_ship_panel() -> void:
|
|||||||
return
|
return
|
||||||
if _drawer_tween != null and _drawer_tween.is_running():
|
if _drawer_tween != null and _drawer_tween.is_running():
|
||||||
_drawer_tween.kill()
|
_drawer_tween.kill()
|
||||||
_ship_panel.size = Vector2(minf(700.0, size.x * 0.55), size.y)
|
_ship_panel.size = Vector2(minf(820.0, size.x), size.y)
|
||||||
_ship_panel.position = Vector2(size.x - _ship_panel.size.x if _panel_open else size.x, 0)
|
_ship_panel.position = Vector2(size.x - _ship_panel.size.x if _panel_open else size.x, 0)
|
||||||
|
|
||||||
func _close_ship_panel() -> void:
|
func _close_ship_panel() -> void:
|
||||||
|
|||||||
@ -27,6 +27,7 @@ func _ready() -> void:
|
|||||||
GameState.captain.changed.connect(_refresh_title)
|
GameState.captain.changed.connect(_refresh_title)
|
||||||
for index in CARGO_SIZE:
|
for index in CARGO_SIZE:
|
||||||
var slot := SLOT_SCENE.instantiate()
|
var slot := SLOT_SCENE.instantiate()
|
||||||
|
slot.name = "Cargo%d" % (index + 1)
|
||||||
slot.set("slot_kind", "cargo")
|
slot.set("slot_kind", "cargo")
|
||||||
slot.set("slot_index", index)
|
slot.set("slot_index", index)
|
||||||
cargo_grid.add_child(slot)
|
cargo_grid.add_child(slot)
|
||||||
|
|||||||
@ -6,7 +6,6 @@ const CATALOG := preload("res://scripts/game/ship_catalog.gd")
|
|||||||
|
|
||||||
@onready var ship_grid: GridContainer = %ShipGrid
|
@onready var ship_grid: GridContainer = %ShipGrid
|
||||||
@onready var close_button: Button = %CloseButton
|
@onready var close_button: Button = %CloseButton
|
||||||
|
|
||||||
var button_group := ButtonGroup.new()
|
var button_group := ButtonGroup.new()
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -14,43 +13,74 @@ func _ready() -> void:
|
|||||||
close_button.pressed.connect(func() -> void: close_requested.emit())
|
close_button.pressed.connect(func() -> void: close_requested.emit())
|
||||||
_load_ships()
|
_load_ships()
|
||||||
|
|
||||||
|
func _frame(accent: Color, highlighted: bool) -> StyleBoxFlat:
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
style.bg_color = Color("142b42") if highlighted else Color("0b192a")
|
||||||
|
style.border_color = accent if highlighted else Color("29435a")
|
||||||
|
style.set_border_width_all(2 if highlighted else 1)
|
||||||
|
style.set_corner_radius_all(10)
|
||||||
|
style.shadow_color = Color(0, 0, 0, 0.3)
|
||||||
|
style.shadow_size = 5
|
||||||
|
return style
|
||||||
|
|
||||||
|
func _label(text: String, font_size: int, color: Color) -> Label:
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = text
|
||||||
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
label.add_theme_font_size_override("font_size", font_size)
|
||||||
|
label.add_theme_color_override("font_color", color)
|
||||||
|
return label
|
||||||
|
|
||||||
func _load_ships() -> void:
|
func _load_ships() -> void:
|
||||||
var selected_ship := CATALOG.for_path(GameState.selected_ship_path)
|
var selected_ship := CATALOG.for_path(GameState.selected_ship_path)
|
||||||
for chassis in CATALOG.SHIPS:
|
for chassis in CATALOG.SHIPS:
|
||||||
var ship_path := CATALOG.texture_path(chassis)
|
var texture := load(CATALOG.texture_path(chassis)) as Texture2D
|
||||||
var texture := load(ship_path) as Texture2D
|
|
||||||
if texture == null:
|
if texture == null:
|
||||||
continue
|
continue
|
||||||
|
var accent: Color = chassis["accent"]
|
||||||
var button := Button.new()
|
var button := Button.new()
|
||||||
button.name = "Ship%d" % int(chassis["number"])
|
button.name = "Ship%d" % int(chassis["number"])
|
||||||
button.custom_minimum_size = Vector2(250, 240)
|
button.custom_minimum_size = Vector2(240, 238)
|
||||||
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
button.toggle_mode = true
|
button.toggle_mode = true
|
||||||
button.button_group = button_group
|
button.button_group = button_group
|
||||||
|
button.add_theme_stylebox_override("normal", _frame(accent, false))
|
||||||
|
for state in ["hover", "pressed", "hover_pressed", "focus"]:
|
||||||
|
button.add_theme_stylebox_override(state, _frame(accent, true))
|
||||||
var contents := VBoxContainer.new()
|
var contents := VBoxContainer.new()
|
||||||
contents.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
contents.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
button.add_child(contents)
|
button.add_child(contents)
|
||||||
contents.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
contents.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
contents.offset_left = 12
|
contents.offset_left = 16
|
||||||
contents.offset_right = -12
|
contents.offset_right = -16
|
||||||
contents.offset_top = 12
|
contents.offset_top = 12
|
||||||
contents.offset_bottom = -12
|
contents.offset_bottom = -12
|
||||||
contents.add_theme_constant_override("separation", 12)
|
contents.add_theme_constant_override("separation", 5)
|
||||||
|
contents.add_child(_label(chassis["name"].to_upper(), 20, Color("edf6ff")))
|
||||||
|
contents.add_child(_label(chassis["role"], 11, accent))
|
||||||
var preview := TextureRect.new()
|
var preview := TextureRect.new()
|
||||||
preview.custom_minimum_size.y = 100
|
preview.custom_minimum_size.y = 110
|
||||||
|
preview.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
preview.texture = texture
|
preview.texture = texture
|
||||||
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
preview.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
preview.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
preview.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||||
contents.add_child(preview)
|
contents.add_child(preview)
|
||||||
var description := Label.new()
|
var stats := GridContainer.new()
|
||||||
description.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
stats.columns = 2
|
||||||
description.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
stats.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
description.text = "%s\n%s\n\n%s" % [chassis["name"], chassis["role"], CATALOG.stats_text(chassis)]
|
stats.add_theme_constant_override("h_separation", 14)
|
||||||
description.add_theme_font_size_override("font_size", 13)
|
stats.add_theme_constant_override("v_separation", 4)
|
||||||
contents.add_child(description)
|
for stat in [["Kadłub", "hull", ""], ["Tarcze", "shields", ""], ["Energia", "energy", ""], ["Prędkość", "speed", " px/s"]]:
|
||||||
button.add_theme_font_size_override("font_size", 13)
|
var value := _label("%s %d%s" % [stat[0], chassis[stat[1]], stat[2]], 13, Color("bfd4e5"))
|
||||||
button.tooltip_text = "%s — %s\nStatystyki bazowe przed bonusami modułów.\n%s" % [chassis["name"], chassis["role"], CATALOG.stats_text(chassis)]
|
value.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
stats.add_child(value)
|
||||||
|
contents.add_child(stats)
|
||||||
|
var launch := _label("WYBIERZ I WYSTARTUJ ›", 11, accent)
|
||||||
|
launch.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||||
|
contents.add_child(launch)
|
||||||
|
button.tooltip_text = "%s\nStatystyki bazowe przed bonusami modułów.\n%s" % [chassis["name"], CATALOG.stats_text(chassis)]
|
||||||
button.pressed.connect(_choose_ship.bind(chassis, button))
|
button.pressed.connect(_choose_ship.bind(chassis, button))
|
||||||
ship_grid.add_child(button)
|
ship_grid.add_child(button)
|
||||||
if chassis["number"] == selected_ship["number"]:
|
if chassis["number"] == selected_ship["number"]:
|
||||||
|
|||||||
@ -31,6 +31,8 @@ func _ready() -> void:
|
|||||||
candidate.additional_modifiers.append(_modifier("damage_percent", 2.0))
|
candidate.additional_modifiers.append(_modifier("damage_percent", 2.0))
|
||||||
candidate.additional_modifiers.append(_modifier("damage_percent", 3.0))
|
candidate.additional_modifiers.append(_modifier("damage_percent", 3.0))
|
||||||
candidate.additional_modifiers.append(_modifier("energy_regeneration", 4.0))
|
candidate.additional_modifiers.append(_modifier("energy_regeneration", 4.0))
|
||||||
|
candidate.additional_modifiers.append(_modifier("shield_on_damage_percent", 2.0))
|
||||||
|
candidate.additional_modifiers.append(_modifier("experience_percent", 5.0))
|
||||||
assert(inventory.add_item(old))
|
assert(inventory.add_item(old))
|
||||||
assert(inventory.move_item("cargo", inventory.cargo.find(old), "module", 0))
|
assert(inventory.move_item("cargo", inventory.cargo.find(old), "module", 0))
|
||||||
assert(inventory.add_item(candidate))
|
assert(inventory.add_item(candidate))
|
||||||
@ -41,8 +43,7 @@ func _ready() -> void:
|
|||||||
for row in rows:
|
for row in rows:
|
||||||
deltas[row["key"]] = row["delta"]
|
deltas[row["key"]] = row["delta"]
|
||||||
assert(is_equal_approx(deltas["max_shields"], 1.0))
|
assert(is_equal_approx(deltas["max_shields"], 1.0))
|
||||||
var weapon: ItemInstance = inventory.weapon_slots[0]
|
assert(is_equal_approx(deltas["damage_percent"], -5.0))
|
||||||
assert(is_equal_approx(deltas["weapon_damage_0"], weapon.get_stat_total("damage") * -0.05))
|
|
||||||
assert(is_equal_approx(deltas["shield_regeneration"], -1.0))
|
assert(is_equal_approx(deltas["shield_regeneration"], -1.0))
|
||||||
assert(is_equal_approx(deltas["energy_regeneration"], 2.0))
|
assert(is_equal_approx(deltas["energy_regeneration"], 2.0))
|
||||||
assert(inventory.get_item_comparison(old, old).is_empty())
|
assert(inventory.get_item_comparison(old, old).is_empty())
|
||||||
@ -83,9 +84,13 @@ func _ready() -> void:
|
|||||||
assert(columns.get_child_count() == 3)
|
assert(columns.get_child_count() == 3)
|
||||||
var comparison: RichTextLabel = columns.get_child(2)
|
var comparison: RichTextLabel = columns.get_child(2)
|
||||||
assert(comparison.get_parsed_text().contains("Tarcze: +1.00 pkt"))
|
assert(comparison.get_parsed_text().contains("Tarcze: +1.00 pkt"))
|
||||||
assert(comparison.get_parsed_text().contains("Śr. obrażenia [LPM]:"))
|
assert(comparison.get_parsed_text().contains("Obrażenia broni: -5.00 %"))
|
||||||
|
assert(comparison.get_parsed_text().contains("Odzysk tarcz z obrażeń: +2.00 %"))
|
||||||
|
assert(comparison.get_parsed_text().contains("Doświadczenie: +5.00 %"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("100 DMG"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("EXP /"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("[LPM]"))
|
||||||
assert(not comparison.get_parsed_text().contains("→"))
|
assert(not comparison.get_parsed_text().contains("→"))
|
||||||
assert(not comparison.get_parsed_text().contains("%"))
|
|
||||||
assert(not comparison.get_parsed_text().contains("p.p."))
|
assert(not comparison.get_parsed_text().contains("p.p."))
|
||||||
assert(comparison.get_parsed_text().contains("Regeneracja tarcz: -1.00 pkt/s"))
|
assert(comparison.get_parsed_text().contains("Regeneracja tarcz: -1.00 pkt/s"))
|
||||||
var debug: Label = hud.get_node("DebugScroll/DebugInfo")
|
var debug: Label = hud.get_node("DebugScroll/DebugInfo")
|
||||||
|
|||||||
@ -13,16 +13,26 @@ func _ready() -> void:
|
|||||||
for enemy in get_tree().get_nodes_in_group("enemies"):
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||||
enemy.set_physics_process(false)
|
enemy.set_physics_process(false)
|
||||||
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||||
|
var extension_index := 0
|
||||||
for definition in GENERATOR.DEFINITIONS:
|
for definition in GENERATOR.DEFINITIONS:
|
||||||
assert(definition.icon != null)
|
assert(definition.icon != null)
|
||||||
assert(definition.icon.get_width() == definition.icon.get_height())
|
assert(definition.icon.get_width() == definition.icon.get_height())
|
||||||
if definition.item_id in ["reinforced_shield", "hull_plating", "engine_extension", "compact_generator", "ship_computer", "beam_laser", "machine_gun", "plasma_cannon", "missile_launcher", "unguided_missile"]:
|
if definition.item_id in ["reinforced_shield", "hull_plating", "engine_extension", "compact_generator", "ship_computer", "beam_laser", "machine_gun", "plasma_cannon", "missile_launcher", "unguided_missile", "afterburner", "shield_charge", "repair_drones"]:
|
||||||
assert(inventory.add_item(GENERATOR.generate_for_definition(definition, 8)))
|
assert(inventory.add_item(GENERATOR.generate_for_definition(definition, 8)))
|
||||||
var category_index := ShipInventory.MODULE_CATEGORIES.find(definition.category)
|
var category_index := ShipInventory.MODULE_CATEGORIES.find(definition.category)
|
||||||
if category_index >= 0 and inventory.module_slots[category_index] == null:
|
if category_index >= 0 and inventory.module_slots[category_index] == null:
|
||||||
var item := GENERATOR.generate_for_definition(definition, 8)
|
var item := GENERATOR.generate_for_definition(definition, 8)
|
||||||
assert(inventory.add_item(item))
|
assert(inventory.add_item(item))
|
||||||
assert(inventory.move_item("cargo", inventory.cargo.find(item), "module", category_index))
|
assert(inventory.move_item("cargo", inventory.cargo.find(item), "module", category_index))
|
||||||
|
if definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
|
var extension := GENERATOR.generate_for_definition(definition, 8)
|
||||||
|
assert(inventory.add_item(extension))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(extension), "extension", extension_index))
|
||||||
|
extension_index += 1
|
||||||
|
GameState.captain.parts = 20
|
||||||
|
ship.set("hull", ship.get("max_hull") - 10)
|
||||||
|
ship.set("shields", ship.get("max_shields") - 20)
|
||||||
|
ship.set("energy", ship.get("max_energy"))
|
||||||
var hud := game.get_node("HUD")
|
var hud := game.get_node("HUD")
|
||||||
hud._toggle_inventory()
|
hud._toggle_inventory()
|
||||||
await get_tree().create_timer(0.3).timeout
|
await get_tree().create_timer(0.3).timeout
|
||||||
@ -36,4 +46,14 @@ func _ready() -> void:
|
|||||||
var style: StyleBoxFlat = slot.get_theme_stylebox("panel")
|
var style: StyleBoxFlat = slot.get_theme_stylebox("panel")
|
||||||
assert(style.bg_color == item.get_background_color())
|
assert(style.bg_color == item.get_background_color())
|
||||||
assert(style.border_color == item.get_type_color())
|
assert(style.border_color == item.get_type_color())
|
||||||
|
var salvage: Button = slot.get_node("ActionOverlay/SalvageButton")
|
||||||
|
assert(salvage.icon != null and salvage.text.is_empty())
|
||||||
|
assert(slot.get_global_rect().encloses(salvage.get_global_rect()))
|
||||||
|
for index in extension_index:
|
||||||
|
var ability_button: Button = hud._ability_buttons[index]
|
||||||
|
assert(ability_button.icon == inventory.extension_slots[index].definition.icon)
|
||||||
|
assert(ability_button.text.is_empty())
|
||||||
|
assert(ability_button.size.x < 64 * 0.8)
|
||||||
|
assert(ability_button.size.y < 64 * 0.8)
|
||||||
|
assert(inventory.extension_slots[2].definition.icon != preload("res://resources/items/hull_plating.tres").icon)
|
||||||
print("ITEM_ICONS_TEST: PASS square textures and slots, icon assignment, rarity backgrounds and borders, inventory and equipment")
|
print("ITEM_ICONS_TEST: PASS square textures and slots, icon assignment, rarity backgrounds and borders, inventory and equipment")
|
||||||
|
|||||||
80
tests/items/weapon_comparison_test.gd
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
extends Node
|
||||||
|
const GAME := preload("res://scenes/game/game.tscn")
|
||||||
|
|
||||||
|
func weapon(damage: float, interval: float = 0.5, missile: bool = false) -> ItemInstance:
|
||||||
|
var item := ItemInstance.new()
|
||||||
|
item.definition = preload("res://resources/items/plasma_cannon.tres").duplicate()
|
||||||
|
item.definition.fire_interval = interval
|
||||||
|
if missile:
|
||||||
|
item.definition.weapon_kind = ItemDefinition.WeaponKind.MISSILE
|
||||||
|
item.damage_min = damage
|
||||||
|
item.damage_max = damage
|
||||||
|
return item
|
||||||
|
|
||||||
|
func modifier(item: ItemInstance, key: String, value: float) -> void:
|
||||||
|
var addon := ItemStatModifier.new()
|
||||||
|
addon.stat_key = key
|
||||||
|
addon.value = value
|
||||||
|
item.additional_modifiers.append(addon)
|
||||||
|
|
||||||
|
func delta_for(comparison: Dictionary, key: String) -> float:
|
||||||
|
for row in comparison["stats"]:
|
||||||
|
if row["key"] == key:
|
||||||
|
return row["delta"]
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
GameState.start_new_run()
|
||||||
|
var game := GAME.instantiate()
|
||||||
|
add_child(game)
|
||||||
|
game.set_physics_process(false)
|
||||||
|
var ship := game.get_node("PlayerShip")
|
||||||
|
ship.set_physics_process(false)
|
||||||
|
ship.get_node("WeaponController").set_physics_process(false)
|
||||||
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||||
|
enemy.set_physics_process(false)
|
||||||
|
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||||
|
var old_first := weapon(10)
|
||||||
|
var old_second := weapon(20)
|
||||||
|
inventory.weapon_slots.assign([old_first, old_second, null])
|
||||||
|
var candidate := weapon(12, 0.4)
|
||||||
|
for index in 3:
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(candidate, index)["dps_delta"], [10.0, -10.0, 30.0][index]))
|
||||||
|
modifier(old_first, "credits_percent", 4)
|
||||||
|
modifier(old_second, "credits_percent", 9)
|
||||||
|
modifier(candidate, "credits_percent", 6)
|
||||||
|
for index in 3:
|
||||||
|
assert(is_equal_approx(delta_for(inventory.get_weapon_comparison(candidate, index), "credits_percent"), [2.0, -3.0, 6.0][index]))
|
||||||
|
modifier(old_first, "missile_cooldown_reduction", 0.5)
|
||||||
|
var rocket := weapon(40, 0.1, true)
|
||||||
|
modifier(rocket, "missile_cooldown_reduction", 2)
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(rocket, 0)["dps_delta"], 40.0 / 3.0 - 20.0))
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(rocket, 2)["dps_delta"], 40.0 / 2.5))
|
||||||
|
modifier(rocket, "missile_cooldown_reduction", 100)
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(rocket, 2)["dps_delta"], 40.0))
|
||||||
|
modifier(old_first, "damage_percent", 5)
|
||||||
|
modifier(candidate, "damage_percent", 20)
|
||||||
|
modifier(candidate, "critical_chance_percent", 10)
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(candidate, 0)["dps_delta"], 39.6 - 21.0))
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(candidate, 1)["dps_delta"], 41.25 - 42.0))
|
||||||
|
modifier(candidate, "damage", 3)
|
||||||
|
assert(is_equal_approx(delta_for(inventory.get_weapon_comparison(candidate, 0), "flat_damage_addon"), 3.0))
|
||||||
|
assert(is_equal_approx(inventory.get_weapon_comparison(candidate, 0)["dps_delta"], 49.5 - 21.0))
|
||||||
|
assert(inventory.weapon_slots[0] == old_first and inventory.weapon_slots[1] == old_second and inventory.weapon_slots[2] == null)
|
||||||
|
assert(inventory.missile_ammunition == ShipInventory.STARTING_MISSILE_AMMUNITION)
|
||||||
|
assert(inventory.add_item(candidate))
|
||||||
|
inventory._recalculate_ship_stats()
|
||||||
|
inventory.inventory_changed.emit()
|
||||||
|
var hud := game.get_node("HUD/HUDRoot")
|
||||||
|
var slot := preload("res://scenes/ui/inventory_slot_view.tscn").instantiate()
|
||||||
|
slot.slot_index = inventory.cargo.find(candidate)
|
||||||
|
hud.add_child(slot)
|
||||||
|
slot.hide()
|
||||||
|
var tooltip: PanelContainer = slot._make_custom_tooltip(candidate.get_tooltip_text())
|
||||||
|
hud.add_child(tooltip)
|
||||||
|
tooltip.position = Vector2(340, 100)
|
||||||
|
assert(tooltip.get_child(0).get_child(2).name == "WeaponComparison")
|
||||||
|
await get_tree().process_frame
|
||||||
|
await get_tree().process_frame
|
||||||
|
assert(tooltip.size.x < 1100 and tooltip.size.y < 620)
|
||||||
|
print("WEAPON_COMPARISON_TEST: PASS three slot DPS, empty slot, affix gains/losses, projected global bonuses, crits, missile cooldown and clamp, no inventory mutation, compact table")
|
||||||
1
tests/items/weapon_comparison_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://du6051e32i5k7
|
||||||
4
tests/items/weapon_comparison_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/items/weapon_comparison_test.gd" id="1"]
|
||||||
|
[node name="WeaponComparisonTest" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
@ -31,6 +31,9 @@ func _ready() -> void:
|
|||||||
poi.take_weapon_hit(1)
|
poi.take_weapon_hit(1)
|
||||||
assert(poi._claimed)
|
assert(poi._claimed)
|
||||||
else:
|
else:
|
||||||
|
if kind == "wreck":
|
||||||
|
assert(poi.has_node("WreckSprite"))
|
||||||
|
assert(poi.WRECK_TEXTURES.has(poi.get_node("WreckSprite").texture))
|
||||||
assert(poi.claim())
|
assert(poi.claim())
|
||||||
assert(not poi.claim())
|
assert(not poi.claim())
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|||||||
@ -21,8 +21,17 @@ func _ready() -> void:
|
|||||||
var drawer := root.get_node("ShipDrawer") as Control
|
var drawer := root.get_node("ShipDrawer") as Control
|
||||||
var toggle := root.get_node("ShipToggle") as Button
|
var toggle := root.get_node("ShipToggle") as Button
|
||||||
var captain := root.get_node("CaptainPanel")
|
var captain := root.get_node("CaptainPanel")
|
||||||
|
assert(captain._collapsed and not captain.get_node("Contents/Skills").visible)
|
||||||
|
assert(not hud._debug_expanded and not hud.debug_info.visible)
|
||||||
|
assert(not hud._sidebar_open and not drawer.visible)
|
||||||
|
assert(not hud.inventory_panel.visible)
|
||||||
|
toggle.pressed.emit()
|
||||||
|
captain._toggle_collapsed()
|
||||||
|
await get_tree().create_timer(0.3).timeout
|
||||||
var equipment := drawer.get_node("Scroll/Contents/ShipEquipmentPanel")
|
var equipment := drawer.get_node("Scroll/Contents/ShipEquipmentPanel")
|
||||||
assert(captain.get_parent() != equipment.get_parent())
|
assert(captain.get_parent() != equipment.get_parent())
|
||||||
|
assert(drawer.scale.is_equal_approx(Vector2.ONE * 0.8))
|
||||||
|
assert(hud.inventory_panel.scale.is_equal_approx(Vector2.ONE * 0.8))
|
||||||
assert(captain.get_node("Contents/PortraitRow/AvatarFrame/CaptainAvatar").texture != null)
|
assert(captain.get_node("Contents/PortraitRow/AvatarFrame/CaptainAvatar").texture != null)
|
||||||
assert(root.has_node("Cockpit"))
|
assert(root.has_node("Cockpit"))
|
||||||
var cockpit := root.get_node("Cockpit") as Control
|
var cockpit := root.get_node("Cockpit") as Control
|
||||||
@ -73,7 +82,7 @@ func _ready() -> void:
|
|||||||
assert(not drawer.visible)
|
assert(not drawer.visible)
|
||||||
toggle.pressed.emit()
|
toggle.pressed.emit()
|
||||||
await get_tree().create_timer(0.3).timeout
|
await get_tree().create_timer(0.3).timeout
|
||||||
assert(drawer.visible and is_equal_approx(drawer.position.x + drawer.size.x, root.size.x - 8.0))
|
assert(drawer.visible and is_equal_approx(drawer.position.x + drawer.size.x * drawer.scale.x, root.size.x - 8.0))
|
||||||
GameState.captain.learning_points = 1
|
GameState.captain.learning_points = 1
|
||||||
GameState.captain.emit_changed()
|
GameState.captain.emit_changed()
|
||||||
captain.get_node("Contents/Skills/gunner/Train_gunner").pressed.emit()
|
captain.get_node("Contents/Skills/gunner/Train_gunner").pressed.emit()
|
||||||
|
|||||||
@ -23,6 +23,8 @@ func _ready() -> void:
|
|||||||
assert(is_equal_approx(panel.position.x + panel.size.x, menu.size.x))
|
assert(is_equal_approx(panel.position.x + panel.size.x, menu.size.x))
|
||||||
var grid := panel.get_node("Layout/ShipScroll/ShipGrid") as GridContainer
|
var grid := panel.get_node("Layout/ShipScroll/ShipGrid") as GridContainer
|
||||||
assert(grid.columns == 2 and grid.get_child_count() == 4)
|
assert(grid.columns == 2 and grid.get_child_count() == 4)
|
||||||
|
assert(not panel.get_node("Layout/ShipScroll").get_v_scroll_bar().visible)
|
||||||
|
assert(not panel.get_node("Layout/ShipScroll").get_h_scroll_bar().visible)
|
||||||
assert(not panel.has_node("Layout/Footer/ContinueButton"))
|
assert(not panel.has_node("Layout/Footer/ContinueButton"))
|
||||||
panel.get_node("Layout/Footer/CloseButton").pressed.emit()
|
panel.get_node("Layout/Footer/CloseButton").pressed.emit()
|
||||||
await get_tree().create_timer(0.25).timeout
|
await get_tree().create_timer(0.25).timeout
|
||||||
|
|||||||