Duzo zmian
70
assets/art_prompts.json
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"tool": "built-in imagegen",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"id": "shield",
|
||||||
|
"path": "assets/icons/shield.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: compact shield generator with luminous cyan hexagonal force-field dome. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "armor",
|
||||||
|
"path": "assets/icons/armor.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: layered spaceship armor plating, heavy beveled gunmetal plates with orange rivets. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "computer",
|
||||||
|
"path": "assets/icons/computer.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: ship computer processor core, precision circuit board and cyan holographic microchip. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "engine",
|
||||||
|
"path": "assets/icons/engine.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: spaceship engine turbine nozzle with bright blue exhaust glow. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "reactor",
|
||||||
|
"path": "assets/icons/reactor.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: fusion reactor, circular magnetic containment chamber with amber energy core. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "laser",
|
||||||
|
"path": "assets/icons/laser.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: sleek spaceship laser cannon, single precision barrel emitting narrow red beam. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "machine_gun",
|
||||||
|
"path": "assets/icons/machine_gun.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: spaceship automatic gun, rotary multi-barrel cannon with brass ammunition belt. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "plasma",
|
||||||
|
"path": "assets/icons/plasma.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: heavy plasma cannon, short thick barrel and violet plasma chamber. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "homing_missile",
|
||||||
|
"path": "assets/icons/homing_missile.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: guided missile launcher pod, missile with fins and a small cyan targeting radar ring. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "unguided_missile",
|
||||||
|
"path": "assets/icons/unguided_missile.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: square sci-fi equipment inventory icon. Subject: unguided rocket launcher pod, chunky rockets with orange exhaust, no targeting ring. One centered distinct item, occupying 80% of the square. Premium polished game item art, detailed gunmetal machinery, crisp silhouette legible at 64 pixels, dramatic soft studio lighting, restrained cyan and amber accents. Consistent three-quarter view. Transparent background. No text, frame, border, UI tile, background scenery, watermark or other items."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "asteroid_rock",
|
||||||
|
"path": "assets/asteroids/asteroid_rock.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down asteroid sprite for a 2D space game. Subject: irregular rugged charcoal-gray asteroid with deep craters and sharp fractured ridges. Square composition, single object centered, occupying 82% of the canvas. Polished painted realistic game art, excellent silhouette at 70 pixels, neutral lighting from upper left, subtle three-dimensional volume. Transparent background. No text, border, stars, shadow outside object, UI, other objects, or glow."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "asteroid_metal",
|
||||||
|
"path": "assets/asteroids/asteroid_metal.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down asteroid sprite for a 2D space game. Subject: angular dense iron asteroid with dark metallic striations and sparse copper mineral seams. Square composition, single object centered, occupying 82% of the canvas. Polished painted realistic game art, excellent silhouette at 70 pixels, neutral lighting from upper left, subtle three-dimensional volume. Transparent background. No text, border, stars, shadow outside object, UI, other objects, or glow."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "asteroid_ice",
|
||||||
|
"path": "assets/asteroids/asteroid_ice.png",
|
||||||
|
"prompt": "Use case: stylized-concept. Asset type: isolated top-down asteroid sprite for a 2D space game. Subject: rounded fractured gray asteroid with icy blue crystalline deposits and small craters. Square composition, single object centered, occupying 82% of the canvas. Polished painted realistic game art, excellent silhouette at 70 pixels, neutral lighting from upper left, subtle three-dimensional volume. Transparent background. No text, border, stars, shadow outside object, UI, other objects, or glow."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
assets/asteroids/asteroid_ice.png
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
40
assets/asteroids/asteroid_ice.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bqsxivk08rrv1"
|
||||||
|
path="res://.godot/imported/asteroid_ice.png-0d420456aba47c55a85abbd8896759f2.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/asteroids/asteroid_ice.png"
|
||||||
|
dest_files=["res://.godot/imported/asteroid_ice.png-0d420456aba47c55a85abbd8896759f2.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/asteroids/asteroid_metal.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
40
assets/asteroids/asteroid_metal.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dknnnjlnfiokv"
|
||||||
|
path="res://.godot/imported/asteroid_metal.png-260765715b40227a400ab8450694da75.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/asteroids/asteroid_metal.png"
|
||||||
|
dest_files=["res://.godot/imported/asteroid_metal.png-260765715b40227a400ab8450694da75.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/asteroids/asteroid_rock.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
40
assets/asteroids/asteroid_rock.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://x70qj5c7yurt"
|
||||||
|
path="res://.godot/imported/asteroid_rock.png-679dcdbe656749145612318b46f7c3d4.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/asteroids/asteroid_rock.png"
|
||||||
|
dest_files=["res://.godot/imported/asteroid_rock.png-679dcdbe656749145612318b46f7c3d4.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/avatars/captain.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
40
assets/avatars/captain.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dumlma4agiydf"
|
||||||
|
path="res://.godot/imported/captain.png-9a0afd3b17a97167234f3e3ea4d8c400.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/avatars/captain.png"
|
||||||
|
dest_files=["res://.godot/imported/captain.png-9a0afd3b17a97167234f3e3ea4d8c400.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
assets/avatars/captain.prompt.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Generated with the built-in imagegen tool.
|
||||||
|
|
||||||
|
Use case: stylized-concept. Asset type: square captain avatar portrait for a polished sci-fi spaceship game HUD, legible at 80 pixels. Subject: experienced adult male space captain, short dark hair with silver temples, subtle stubble, calm focused expression, navy flight suit with small amber and cyan accents, no logos. Composition: centered head and shoulders, face large, square crop. Style: polished hand-painted game concept art, realistic anatomy, crisp silhouette, restrained detail. Lighting: cyan rim light and warm amber key light. Background: dark navy cockpit blur. No text, no watermark, no decorative frame.
|
||||||
BIN
assets/icons/armor.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
40
assets/icons/armor.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://twjypsovswrj"
|
||||||
|
path="res://.godot/imported/armor.png-cd0de3e584bc414792dc7177f7f97118.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/armor.png"
|
||||||
|
dest_files=["res://.godot/imported/armor.png-cd0de3e584bc414792dc7177f7f97118.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/computer.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
40
assets/icons/computer.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dswokqx8fjbl7"
|
||||||
|
path="res://.godot/imported/computer.png-06f9e1e3ec9eb03dac33e53d3e226b18.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/computer.png"
|
||||||
|
dest_files=["res://.godot/imported/computer.png-06f9e1e3ec9eb03dac33e53d3e226b18.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/engine.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
40
assets/icons/engine.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bfsy4ts4kr5iu"
|
||||||
|
path="res://.godot/imported/engine.png-90c3579541e0f551c023fcf5f45c8938.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/engine.png"
|
||||||
|
dest_files=["res://.godot/imported/engine.png-90c3579541e0f551c023fcf5f45c8938.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/homing_missile.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
40
assets/icons/homing_missile.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cmlhgaubsmoso"
|
||||||
|
path="res://.godot/imported/homing_missile.png-0ff3770387c0b8d591a6d726f544d23d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/homing_missile.png"
|
||||||
|
dest_files=["res://.godot/imported/homing_missile.png-0ff3770387c0b8d591a6d726f544d23d.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/laser.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
40
assets/icons/laser.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cg31nor3aqfcd"
|
||||||
|
path="res://.godot/imported/laser.png-78f84fc3b728b76788f1d7e6bb3d09a0.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/laser.png"
|
||||||
|
dest_files=["res://.godot/imported/laser.png-78f84fc3b728b76788f1d7e6bb3d09a0.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/machine_gun.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
40
assets/icons/machine_gun.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dglx1hqhd660y"
|
||||||
|
path="res://.godot/imported/machine_gun.png-82b5627260e455aa7509fcb24baf4ee1.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/machine_gun.png"
|
||||||
|
dest_files=["res://.godot/imported/machine_gun.png-82b5627260e455aa7509fcb24baf4ee1.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/plasma.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
40
assets/icons/plasma.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bcysvo1y1k2n"
|
||||||
|
path="res://.godot/imported/plasma.png-010e12ed95db210261727cb258030992.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/plasma.png"
|
||||||
|
dest_files=["res://.godot/imported/plasma.png-010e12ed95db210261727cb258030992.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/reactor.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
40
assets/icons/reactor.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://civi7r36r2ua4"
|
||||||
|
path="res://.godot/imported/reactor.png-55fcc7bf0233d2989c491f5381ead349.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/reactor.png"
|
||||||
|
dest_files=["res://.godot/imported/reactor.png-55fcc7bf0233d2989c491f5381ead349.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.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
40
assets/icons/shield.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cmeso5ns28mil"
|
||||||
|
path="res://.godot/imported/shield.png-dc46181106b01d9c5b9cf3dd1ba81451.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/shield.png"
|
||||||
|
dest_files=["res://.godot/imported/shield.png-dc46181106b01d9c5b9cf3dd1ba81451.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/unguided_missile.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
40
assets/icons/unguided_missile.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b8oeu45j01e17"
|
||||||
|
path="res://.godot/imported/unguided_missile.png-1dd7a9dcb8b847e813c29b7540ac1098.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/icons/unguided_missile.png"
|
||||||
|
dest_files=["res://.godot/imported/unguided_missile.png-1dd7a9dcb8b847e813c29b7540ac1098.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/other/asteroids.jpg
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
40
assets/other/asteroids.jpg.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bnjux8sn6b5xl"
|
||||||
|
path="res://.godot/imported/asteroids.jpg-2fcfc4129a9d368d61d5aef72c84c9ad.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/other/asteroids.jpg"
|
||||||
|
dest_files=["res://.godot/imported/asteroids.jpg-2fcfc4129a9d368d61d5aef72c84c9ad.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
|
||||||
8
resources/asteroid_cutout.gdshader
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
shader_type canvas_item;
|
||||||
|
|
||||||
|
// Remove the white backing from the original JPEG atlas at render time.
|
||||||
|
void fragment() {
|
||||||
|
vec4 texel = texture(TEXTURE, UV);
|
||||||
|
float background = smoothstep(0.86, 0.98, min(texel.r, min(texel.g, texel.b)));
|
||||||
|
COLOR.a *= 1.0 - background;
|
||||||
|
}
|
||||||
1
resources/asteroid_cutout.gdshader.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://c6nuwnxc0kygw
|
||||||
@ -9,7 +9,7 @@ display_name = "Kredyty"
|
|||||||
stat_key = "credits_percent"
|
stat_key = "credits_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 2
|
minimum_value_level_1 = 2
|
||||||
maximum_value_level_1 = 5
|
maximum_value_level_1 = 5
|
||||||
minimum_value_level_1000 = 40
|
minimum_value_level_1000 = 40
|
||||||
|
|||||||
@ -8,7 +8,7 @@ affix_id = "critical_chance_percent"
|
|||||||
display_name = "Szansa na trafienie krytyczne"
|
display_name = "Szansa na trafienie krytyczne"
|
||||||
stat_key = "critical_chance_percent"
|
stat_key = "critical_chance_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 1.0
|
minimum_value_level_1 = 1.0
|
||||||
maximum_value_level_1 = 2.0
|
maximum_value_level_1 = 2.0
|
||||||
minimum_value_level_1000 = 10.0
|
minimum_value_level_1000 = 10.0
|
||||||
|
|||||||
@ -8,7 +8,7 @@ affix_id = "critical_damage_percent"
|
|||||||
display_name = "Obrażenia krytyczne"
|
display_name = "Obrażenia krytyczne"
|
||||||
stat_key = "critical_damage_percent"
|
stat_key = "critical_damage_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 5.0
|
minimum_value_level_1 = 5.0
|
||||||
maximum_value_level_1 = 10.0
|
maximum_value_level_1 = 10.0
|
||||||
minimum_value_level_1000 = 50.0
|
minimum_value_level_1000 = 50.0
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Regeneracja energii"
|
|||||||
stat_key = "energy_regeneration"
|
stat_key = "energy_regeneration"
|
||||||
unit = "/s"
|
unit = "/s"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 0.2
|
minimum_value_level_1 = 0.2
|
||||||
maximum_value_level_1 = 0.5
|
maximum_value_level_1 = 0.5
|
||||||
minimum_value_level_1000 = 100
|
minimum_value_level_1000 = 100
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Doświadczenie (EXP)"
|
|||||||
stat_key = "experience_percent"
|
stat_key = "experience_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 2
|
minimum_value_level_1 = 2
|
||||||
maximum_value_level_1 = 5
|
maximum_value_level_1 = 5
|
||||||
minimum_value_level_1000 = 40
|
minimum_value_level_1000 = 40
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Kadłub"
|
|||||||
stat_key = "hull_percent"
|
stat_key = "hull_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 1
|
minimum_value_level_1 = 1
|
||||||
maximum_value_level_1 = 3
|
maximum_value_level_1 = 3
|
||||||
minimum_value_level_1000 = 25
|
minimum_value_level_1000 = 25
|
||||||
|
|||||||
@ -6,7 +6,7 @@ affix_id = "missile_cooldown"
|
|||||||
display_name = "Skrócenie cooldownu rakiet"
|
display_name = "Skrócenie cooldownu rakiet"
|
||||||
stat_key = "missile_cooldown_reduction"
|
stat_key = "missile_cooldown_reduction"
|
||||||
unit = "s"
|
unit = "s"
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 0.1
|
minimum_value_level_1 = 0.1
|
||||||
maximum_value_level_1 = 0.15
|
maximum_value_level_1 = 0.15
|
||||||
minimum_value_level_1000 = 1.0
|
minimum_value_level_1000 = 1.0
|
||||||
|
|||||||
@ -7,7 +7,7 @@ display_name = "Odzysk tarcz z obrażeń"
|
|||||||
description = "Globalnie odnawia tarcze o procent faktycznie zadanych obrażeń każdą bronią."
|
description = "Globalnie odnawia tarcze o procent faktycznie zadanych obrażeń każdą bronią."
|
||||||
stat_key = "shield_on_damage_percent"
|
stat_key = "shield_on_damage_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 1.0
|
minimum_value_level_1 = 1.0
|
||||||
maximum_value_level_1 = 1.0
|
maximum_value_level_1 = 1.0
|
||||||
minimum_value_level_1000 = 5.0
|
minimum_value_level_1000 = 5.0
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Tarcze"
|
|||||||
stat_key = "shield_percent"
|
stat_key = "shield_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 1
|
minimum_value_level_1 = 1
|
||||||
maximum_value_level_1 = 3
|
maximum_value_level_1 = 3
|
||||||
minimum_value_level_1000 = 25
|
minimum_value_level_1000 = 25
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Regeneracja tarcz"
|
|||||||
stat_key = "shield_regeneration"
|
stat_key = "shield_regeneration"
|
||||||
unit = "/s"
|
unit = "/s"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 0.5
|
minimum_value_level_1 = 0.5
|
||||||
maximum_value_level_1 = 1
|
maximum_value_level_1 = 1
|
||||||
minimum_value_level_1000 = 200
|
minimum_value_level_1000 = 200
|
||||||
|
|||||||
@ -9,7 +9,7 @@ display_name = "Prędkość statku"
|
|||||||
stat_key = "speed_percent"
|
stat_key = "speed_percent"
|
||||||
unit = "%"
|
unit = "%"
|
||||||
selection_weight = 1.0
|
selection_weight = 1.0
|
||||||
category_mask = 63
|
category_mask = 95
|
||||||
minimum_value_level_1 = 1
|
minimum_value_level_1 = 1
|
||||||
maximum_value_level_1 = 2
|
maximum_value_level_1 = 2
|
||||||
minimum_value_level_1000 = 15
|
minimum_value_level_1000 = 15
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
[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"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
display_name = "Dopalacz"
|
display_name = "Dopalacz"
|
||||||
@ -10,6 +12,7 @@ description = "Szybko rozpędza do 300% zwykłej prędkości (+200%), następnie
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "afterburner"
|
item_id = "afterburner"
|
||||||
display_name = "Dopalacz"
|
display_name = "Dopalacz"
|
||||||
category = 5
|
category = 5
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/laser.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "beam_laser"
|
item_id = "beam_laser"
|
||||||
display_name = "Laser wiązkowy"
|
display_name = "Laser wiązkowy"
|
||||||
category = 0
|
category = 0
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/reactor.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "compact_generator"
|
item_id = "compact_generator"
|
||||||
display_name = "Kompaktowy generator"
|
display_name = "Reaktor"
|
||||||
category = 3
|
category = 3
|
||||||
description = "Zwiększa maksymalną pojemność energii."
|
description = "Zwiększa maksymalną pojemność energii."
|
||||||
primary_stat = "max_energy"
|
primary_stat = "max_energy"
|
||||||
|
|||||||
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" uid="uid://d2fdtd4wjk7d" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/engine.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "engine_extension"
|
item_id = "engine_extension"
|
||||||
display_name = "Ulepszony silnik"
|
display_name = "Silnik"
|
||||||
description = "Pasywny moduł prędkości. Na poziomie 1 bonus wynosi 1–5 px/s i rośnie wraz z poziomem przedmiotu."
|
description = "Pasywny moduł prędkości. Na poziomie 1 bonus wynosi 1–5 px/s i rośnie wraz z poziomem przedmiotu."
|
||||||
primary_stat = "max_speed"
|
primary_stat = "max_speed"
|
||||||
primary_value = 3.0
|
primary_value = 3.0
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/armor.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "hull_plating"
|
item_id = "hull_plating"
|
||||||
display_name = "Płyty kadłubowe"
|
display_name = "Pancerz"
|
||||||
category = 2
|
category = 2
|
||||||
description = "Zwiększa maksymalną wytrzymałość kadłuba."
|
description = "Zwiększa maksymalną wytrzymałość kadłuba."
|
||||||
primary_stat = "max_hull"
|
primary_stat = "max_hull"
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/machine_gun.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "machine_gun"
|
item_id = "machine_gun"
|
||||||
display_name = "Działko maszynowe"
|
display_name = "Działko maszynowe"
|
||||||
category = 0
|
category = 0
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/homing_missile.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "missile_launcher"
|
item_id = "missile_launcher"
|
||||||
display_name = "Wyrzutnia rakiet naprowadzanych"
|
display_name = "Wyrzutnia rakiet naprowadzanych"
|
||||||
category = 0
|
category = 0
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/plasma.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "plasma_cannon"
|
item_id = "plasma_cannon"
|
||||||
display_name = "Działko plazmowe"
|
display_name = "Działko plazmowe"
|
||||||
category = 0
|
category = 0
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/shield.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "reinforced_shield"
|
item_id = "reinforced_shield"
|
||||||
display_name = "Wzmocniony emiter"
|
display_name = "Tarcze"
|
||||||
category = 1
|
category = 1
|
||||||
description = "Zwiększa maksymalną pojemność tarcz."
|
description = "Zwiększa maksymalną pojemność tarcz."
|
||||||
primary_stat = "max_shields"
|
primary_stat = "max_shields"
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
[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"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
display_name = "Drony naprawcze"
|
display_name = "Drony naprawcze"
|
||||||
@ -10,6 +12,7 @@ description = "Naprawiają tyle kadłuba, ile pozwalają części i brakujące p
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "repair_drones"
|
item_id = "repair_drones"
|
||||||
display_name = "Drony naprawcze"
|
display_name = "Drony naprawcze"
|
||||||
category = 5
|
category = 5
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=4 format=3]
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1"]
|
|
||||||
[ext_resource type="Script" path="res://scripts/abilities/scanner_ability.gd" id="2"]
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
|
||||||
script = ExtResource("2")
|
|
||||||
display_name = "Skaner"
|
|
||||||
description = "Przez 8 sekund pokazuje kierunki do wrogów, asteroid, wraków i planet z antycznymi znaleziskami. Wymaga i zużywa 50% maksymalnej energii."
|
|
||||||
[resource]
|
|
||||||
script = ExtResource("1")
|
|
||||||
item_id = "scanner"
|
|
||||||
display_name = "Skaner"
|
|
||||||
category = 5
|
|
||||||
description = "Aktywne rozszerzenie eksploracyjne. Zamontuj w slocie modułu i aktywuj przypisanym klawiszem 1–6."
|
|
||||||
active_ability = SubResource("Ability")
|
|
||||||
@ -3,6 +3,8 @@
|
|||||||
[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"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Ability"]
|
[sub_resource type="Resource" id="Ability"]
|
||||||
script = ExtResource("2")
|
script = ExtResource("2")
|
||||||
display_name = "Ładowanie tarcz"
|
display_name = "Ładowanie tarcz"
|
||||||
@ -10,6 +12,7 @@ description = "Przywraca 100 punktów tarcz, do ich maksimum. Wymaga i zużywa 1
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "shield_charge"
|
item_id = "shield_charge"
|
||||||
display_name = "Ładowanie tarcz"
|
display_name = "Ładowanie tarcz"
|
||||||
category = 5
|
category = 5
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/shield.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "shield_recharger"
|
item_id = "shield_recharger"
|
||||||
display_name = "Generator tarcz"
|
display_name = "Tarcze"
|
||||||
category = 1
|
category = 1
|
||||||
description = "Odnawia tarcze statku z szybkością 1 punktu na sekundę."
|
description = "Zwiększa maksymalną pojemność tarcz statku."
|
||||||
primary_stat = "shield_regeneration"
|
primary_stat = "max_shields"
|
||||||
primary_value = 1.0
|
primary_value = 15.0
|
||||||
stat_suffix = " tarczy/s"
|
stat_suffix = " tarczy"
|
||||||
|
|||||||
14
resources/items/ship_computer.tres
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[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/computer.png" id="icon"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1")
|
||||||
|
icon = ExtResource("icon")
|
||||||
|
item_id = "ship_computer"
|
||||||
|
display_name = "Komputer"
|
||||||
|
category = 6
|
||||||
|
description = "Zwiększa zasięg stałego skanera wykrywającego wrogów, asteroidy, wraki i antyczne znaleziska."
|
||||||
|
primary_stat = "scanner_range"
|
||||||
|
primary_value = 300.0
|
||||||
|
stat_suffix = " px"
|
||||||
@ -1,7 +1,10 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
[ext_resource type="Texture2D" path="res://assets/icons/unguided_missile.png" id="icon"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
|
icon = ExtResource("icon")
|
||||||
item_id = "unguided_missile"
|
item_id = "unguided_missile"
|
||||||
display_name = "Wyrzutnia rakiet niekierowanych"
|
display_name = "Wyrzutnia rakiet niekierowanych"
|
||||||
category = 0
|
category = 0
|
||||||
|
|||||||
@ -74,8 +74,3 @@ theme_override_font_sizes/font_size = 11
|
|||||||
[node name="Skills" type="VBoxContainer" parent="Contents"]
|
[node name="Skills" type="VBoxContainer" parent="Contents"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/separation = 2
|
theme_override_constants/separation = 2
|
||||||
|
|
||||||
[node name="Critical" type="Label" parent="Contents"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_colors/font_color = Color(0.98, 0.68, 0.5, 1)
|
|
||||||
theme_override_font_sizes/font_size = 10
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Script" path="res://scripts/ui/equipment_slot_view.gd" id="1_slot"]
|
[ext_resource type="Script" path="res://scripts/ui/equipment_slot_view.gd" id="1_slot"]
|
||||||
|
|
||||||
[node name="InventorySlot" type="PanelContainer"]
|
[node name="InventorySlot" type="PanelContainer"]
|
||||||
custom_minimum_size = Vector2(72, 48)
|
custom_minimum_size = Vector2(64, 64)
|
||||||
script = ExtResource("1_slot")
|
script = ExtResource("1_slot")
|
||||||
|
|
||||||
[node name="SlotLabel" type="Label" parent="."]
|
[node name="SlotLabel" type="Label" parent="."]
|
||||||
|
|||||||
@ -39,11 +39,11 @@ theme_override_constants/separation = 6
|
|||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_colors/font_color = Color(0.8, 0.84, 0.88, 1)
|
theme_override_colors/font_color = Color(0.8, 0.84, 0.88, 1)
|
||||||
theme_override_font_sizes/font_size = 12
|
theme_override_font_sizes/font_size = 12
|
||||||
text = "WYPOSAŻENIE STATKU"
|
text = "SYSTEMY POKŁADOWE"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="EquipmentLayout" type="Control" parent="Contents"]
|
[node name="EquipmentLayout" type="Control" parent="Contents"]
|
||||||
custom_minimum_size = Vector2(306, 318)
|
custom_minimum_size = Vector2(284, 456)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
|
||||||
@ -59,92 +59,132 @@ script = ExtResource("1_schematic")
|
|||||||
|
|
||||||
[node name="Weapon1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Weapon1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
offset_left = 14.0
|
||||||
offset_top = 22.0
|
offset_top = 22.0
|
||||||
offset_right = 90.0
|
offset_right = 78.0
|
||||||
offset_bottom = 66.0
|
offset_bottom = 86.0
|
||||||
slot_kind = "weapon"
|
slot_kind = "weapon"
|
||||||
slot_index = 0
|
slot_index = 0
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Weapon2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Weapon2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 216.0
|
offset_left = 206.0
|
||||||
offset_top = 22.0
|
offset_top = 22.0
|
||||||
offset_right = 306.0
|
offset_right = 270.0
|
||||||
offset_bottom = 66.0
|
offset_bottom = 86.0
|
||||||
slot_kind = "weapon"
|
slot_kind = "weapon"
|
||||||
slot_index = 1
|
slot_index = 1
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Missile" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Weapon3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 108.0
|
offset_left = 110.0
|
||||||
offset_top = 22.0
|
offset_top = 22.0
|
||||||
offset_right = 198.0
|
offset_right = 174.0
|
||||||
offset_bottom = 66.0
|
offset_bottom = 86.0
|
||||||
slot_kind = "weapon"
|
slot_kind = "weapon"
|
||||||
slot_index = 2
|
slot_index = 2
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
offset_left = 14.0
|
||||||
offset_top = 100.0
|
offset_top = 108.0
|
||||||
offset_right = 104.0
|
offset_right = 78.0
|
||||||
offset_bottom = 144.0
|
offset_bottom = 172.0
|
||||||
slot_kind = "module"
|
slot_kind = "module"
|
||||||
slot_index = 0
|
slot_index = 0
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 202.0
|
offset_left = 14.0
|
||||||
offset_top = 100.0
|
offset_top = 178.0
|
||||||
offset_right = 306.0
|
offset_right = 78.0
|
||||||
offset_bottom = 144.0
|
offset_bottom = 242.0
|
||||||
slot_kind = "module"
|
slot_kind = "module"
|
||||||
slot_index = 1
|
slot_index = 1
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
offset_left = 14.0
|
||||||
offset_top = 180.0
|
offset_top = 248.0
|
||||||
offset_right = 104.0
|
offset_right = 78.0
|
||||||
offset_bottom = 224.0
|
offset_bottom = 312.0
|
||||||
slot_kind = "module"
|
slot_kind = "module"
|
||||||
slot_index = 2
|
slot_index = 2
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 202.0
|
offset_left = 14.0
|
||||||
offset_top = 180.0
|
offset_top = 318.0
|
||||||
offset_right = 306.0
|
offset_right = 78.0
|
||||||
offset_bottom = 224.0
|
offset_bottom = 382.0
|
||||||
slot_kind = "module"
|
slot_kind = "module"
|
||||||
slot_index = 3
|
slot_index = 3
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
offset_left = 14.0
|
||||||
offset_top = 260.0
|
offset_top = 388.0
|
||||||
offset_right = 104.0
|
offset_right = 78.0
|
||||||
offset_bottom = 304.0
|
offset_bottom = 452.0
|
||||||
slot_kind = "module"
|
slot_kind = "module"
|
||||||
slot_index = 4
|
slot_index = 4
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module6" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Extension1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 202.0
|
offset_left = 206.0
|
||||||
offset_top = 260.0
|
offset_top = 108.0
|
||||||
offset_right = 306.0
|
offset_right = 270.0
|
||||||
offset_bottom = 304.0
|
offset_bottom = 172.0
|
||||||
slot_kind = "module"
|
slot_kind = "extension"
|
||||||
slot_index = 5
|
slot_index = 0
|
||||||
|
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_right = 270.0
|
||||||
|
offset_bottom = 242.0
|
||||||
|
slot_kind = "extension"
|
||||||
|
slot_index = 1
|
||||||
|
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_right = 270.0
|
||||||
|
offset_bottom = 312.0
|
||||||
|
slot_kind = "extension"
|
||||||
|
slot_index = 2
|
||||||
|
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_right = 270.0
|
||||||
|
offset_bottom = 382.0
|
||||||
|
slot_kind = "extension"
|
||||||
|
slot_index = 3
|
||||||
|
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_right = 270.0
|
||||||
|
offset_bottom = 452.0
|
||||||
|
slot_kind = "extension"
|
||||||
|
slot_index = 4
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="InventoryButton" type="Button" parent="Contents"]
|
[node name="InventoryButton" type="Button" parent="Contents"]
|
||||||
|
|||||||
@ -59,12 +59,6 @@ size_flags_horizontal = 3
|
|||||||
theme_override_font_sizes/font_size = 11
|
theme_override_font_sizes/font_size = 11
|
||||||
text = "AMUNICJA: 50"
|
text = "AMUNICJA: 50"
|
||||||
|
|
||||||
[node name="CraftButton" type="Button" parent="Contents/Ammunition"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 11
|
|
||||||
text = "TWÓRZ +100 AMUNICJI (50 części)"
|
|
||||||
tooltip_text = "Zamień 50 części na 100 sztuk amunicji do działka maszynowego."
|
|
||||||
|
|
||||||
[node name="CargoGrid" type="GridContainer" parent="Contents"]
|
[node name="CargoGrid" type="GridContainer" parent="Contents"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 4
|
size_flags_horizontal = 4
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
extends ActiveAbility
|
|
||||||
|
|
||||||
const SCAN_DURATION := 8.0
|
|
||||||
const OVERLAY := preload("res://scripts/ui/scanner_overlay.gd")
|
|
||||||
|
|
||||||
func unavailable_reason(ship: CharacterBody2D) -> String:
|
|
||||||
if ship.has_node("ScannerOverlay"):
|
|
||||||
return "Skaner jest aktywny"
|
|
||||||
return "Wymagane 50% energii" if float(ship.get("energy")) < float(ship.get("max_energy")) * 0.5 else ""
|
|
||||||
|
|
||||||
func activate(ship: CharacterBody2D) -> void:
|
|
||||||
if not unavailable_reason(ship).is_empty():
|
|
||||||
return
|
|
||||||
ship.set("energy", float(ship.get("energy")) - float(ship.get("max_energy")) * 0.5)
|
|
||||||
var layer := CanvasLayer.new()
|
|
||||||
layer.name = "ScannerOverlay"
|
|
||||||
layer.layer = 8
|
|
||||||
ship.add_child(layer)
|
|
||||||
var overlay := Control.new()
|
|
||||||
overlay.set_script(OVERLAY)
|
|
||||||
overlay.set("player", ship)
|
|
||||||
overlay.set("remaining", SCAN_DURATION)
|
|
||||||
layer.add_child(overlay)
|
|
||||||
overlay.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
uid://dhayld6xbljao
|
|
||||||
@ -14,11 +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 := false
|
var _sidebar_open := true
|
||||||
var _sidebar_tween: Tween
|
var _sidebar_tween: Tween
|
||||||
const SIDEBAR_WIDTH := 344.0
|
const SIDEBAR_WIDTH := 306.0
|
||||||
|
var _debug_scroll: ScrollContainer
|
||||||
|
var _captain_panel: PanelContainer
|
||||||
|
var _cockpit: Control
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_sidebar_open = bool(GameState.hud_panel_state.get("ship_open", true))
|
||||||
|
_debug_expanded = bool(GameState.hud_panel_state.get("debug_expanded", true))
|
||||||
|
debug_info.visible = _debug_expanded
|
||||||
var energy_indicator := Node2D.new()
|
var energy_indicator := Node2D.new()
|
||||||
energy_indicator.name = "EnergyIndicator"
|
energy_indicator.name = "EnergyIndicator"
|
||||||
energy_indicator.set_script(preload("res://scripts/game/ship_energy_indicator.gd"))
|
energy_indicator.set_script(preload("res://scripts/game/ship_energy_indicator.gd"))
|
||||||
@ -29,7 +35,9 @@ func _ready() -> void:
|
|||||||
feedback.set_script(preload("res://scripts/ui/combat_feedback.gd"))
|
feedback.set_script(preload("res://scripts/ui/combat_feedback.gd"))
|
||||||
feedback.set("player", player)
|
feedback.set("player", player)
|
||||||
$HUDRoot.add_child(feedback)
|
$HUDRoot.add_child(feedback)
|
||||||
debug_info.add_theme_font_size_override("font_size", 9)
|
debug_info.add_theme_font_size_override("font_size", 10)
|
||||||
|
# The display font has unusually tall vertical metrics; keep debug rows compact.
|
||||||
|
debug_info.add_theme_constant_override("line_spacing", mini(0, 13 - ceili(debug_info.get_theme_font("font").get_height(10))))
|
||||||
_create_sidebar()
|
_create_sidebar()
|
||||||
_inventory_clip = Control.new()
|
_inventory_clip = Control.new()
|
||||||
_inventory_clip.name = "InventoryDrawer"
|
_inventory_clip.name = "InventoryDrawer"
|
||||||
@ -39,21 +47,37 @@ func _ready() -> void:
|
|||||||
inventory_panel.reparent(_inventory_clip, false)
|
inventory_panel.reparent(_inventory_clip, false)
|
||||||
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(780, inventory_panel.get_combined_minimum_size().y)
|
inventory_panel.size = Vector2(560, inventory_panel.get_combined_minimum_size().y)
|
||||||
$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)
|
||||||
inventory_button.pressed.connect(_toggle_inventory)
|
inventory_button.pressed.connect(_toggle_inventory)
|
||||||
_update_debug_toggle()
|
_update_debug_toggle()
|
||||||
_layout_sidebar.call_deferred()
|
_layout_sidebar.call_deferred()
|
||||||
|
if _sidebar_open and bool(GameState.hud_panel_state.get("inventory_open", false)):
|
||||||
|
inventory_panel.call("_set_drawer_open", true)
|
||||||
|
|
||||||
func _create_sidebar() -> void:
|
func _create_sidebar() -> void:
|
||||||
|
_captain_panel = $HUDRoot/CaptainPanel
|
||||||
|
_captain_panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||||
|
_captain_panel.position = Vector2(12, 12)
|
||||||
|
_captain_panel.size = Vector2(320, _captain_panel.get_combined_minimum_size().y)
|
||||||
|
_captain_panel.resized.connect(_layout_debug)
|
||||||
|
_debug_scroll = ScrollContainer.new()
|
||||||
|
_debug_scroll.name = "DebugScroll"
|
||||||
|
_debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||||
|
$HUDRoot.add_child(_debug_scroll)
|
||||||
|
debug_info.reparent(_debug_scroll, false)
|
||||||
|
debug_info.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||||
|
debug_info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
debug_info.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
_sidebar = PanelContainer.new()
|
_sidebar = PanelContainer.new()
|
||||||
_sidebar.name = "CaptainShipDrawer"
|
_sidebar.name = "ShipDrawer"
|
||||||
var style := StyleBoxFlat.new()
|
var style := StyleBoxFlat.new()
|
||||||
style.bg_color = Color(0.018, 0.028, 0.043, 0.97)
|
style.bg_color = Color(0.025, 0.042, 0.064, 0.97)
|
||||||
style.border_color = Color("52677e")
|
style.border_color = Color("376779")
|
||||||
style.set_border_width_all(1)
|
style.set_border_width_all(1)
|
||||||
|
style.set_corner_radius_all(8)
|
||||||
style.set_content_margin_all(8)
|
style.set_content_margin_all(8)
|
||||||
_sidebar.add_theme_stylebox_override("panel", style)
|
_sidebar.add_theme_stylebox_override("panel", style)
|
||||||
$HUDRoot.add_child(_sidebar)
|
$HUDRoot.add_child(_sidebar)
|
||||||
@ -64,50 +88,70 @@ func _create_sidebar() -> void:
|
|||||||
var contents := VBoxContainer.new()
|
var contents := VBoxContainer.new()
|
||||||
contents.name = "Contents"
|
contents.name = "Contents"
|
||||||
contents.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
contents.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
contents.add_theme_constant_override("separation", 8)
|
|
||||||
scroll.add_child(contents)
|
scroll.add_child(contents)
|
||||||
var captain := $HUDRoot/CaptainPanel as PanelContainer
|
|
||||||
var equipment := $HUDRoot/ShipEquipmentPanel as PanelContainer
|
var equipment := $HUDRoot/ShipEquipmentPanel as PanelContainer
|
||||||
for panel in [captain, equipment]:
|
equipment.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||||
panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
equipment.reparent(contents, false)
|
||||||
panel.reparent(contents, false)
|
equipment.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
equipment.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
||||||
panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
var crafting := PanelContainer.new()
|
||||||
if panel == captain:
|
crafting.name = "CraftingPanel"
|
||||||
contents.add_child(HSeparator.new())
|
crafting.set_script(preload("res://scripts/ui/ship_crafting_panel.gd"))
|
||||||
|
equipment.get_node("Contents").add_child(crafting)
|
||||||
|
contents.minimum_size_changed.connect(func() -> void: _layout_sidebar.call_deferred())
|
||||||
_sidebar_toggle = Button.new()
|
_sidebar_toggle = Button.new()
|
||||||
_sidebar_toggle.name = "CaptainShipToggle"
|
_sidebar_toggle.name = "ShipToggle"
|
||||||
_sidebar_toggle.text = "KAPITAN / STATEK ◀"
|
_sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
|
||||||
_sidebar_toggle.add_theme_font_size_override("font_size", 12)
|
_sidebar_toggle.add_theme_font_size_override("font_size", 12)
|
||||||
_sidebar_toggle.focus_mode = Control.FOCUS_NONE
|
_sidebar_toggle.focus_mode = Control.FOCUS_NONE
|
||||||
$HUDRoot.add_child(_sidebar_toggle)
|
$HUDRoot.add_child(_sidebar_toggle)
|
||||||
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
||||||
_sidebar_toggle.offset_left = -210
|
_sidebar_toggle.offset_left = -180
|
||||||
_sidebar_toggle.offset_right = -8
|
_sidebar_toggle.offset_right = -12
|
||||||
_sidebar_toggle.offset_top = 8
|
_sidebar_toggle.offset_top = 12
|
||||||
_sidebar_toggle.offset_bottom = 38
|
_sidebar_toggle.offset_bottom = 40
|
||||||
_sidebar_toggle.pressed.connect(_toggle_sidebar)
|
_sidebar_toggle.pressed.connect(_toggle_sidebar)
|
||||||
_sidebar.hide()
|
_cockpit = Control.new()
|
||||||
|
_cockpit.name = "Cockpit"
|
||||||
|
_cockpit.set_script(preload("res://scripts/ui/flight_cockpit.gd"))
|
||||||
|
_cockpit.set("player", player)
|
||||||
|
_cockpit.set("game", get_parent())
|
||||||
|
$HUDRoot.add_child(_cockpit)
|
||||||
|
_layout_debug()
|
||||||
|
|
||||||
|
func _layout_debug() -> void:
|
||||||
|
if _debug_scroll == null:
|
||||||
|
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_scroll.visible = _debug_expanded
|
||||||
|
|
||||||
func _toggle_sidebar() -> void:
|
func _toggle_sidebar() -> void:
|
||||||
_sidebar_open = not _sidebar_open
|
_sidebar_open = not _sidebar_open
|
||||||
|
GameState.hud_panel_state["ship_open"] = _sidebar_open
|
||||||
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_toggle.text = "ZAMKNIJ ▶" if _sidebar_open else "KAPITAN / STATEK ◀"
|
_sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
|
||||||
if _sidebar_open:
|
if _sidebar_open:
|
||||||
_sidebar.show()
|
_sidebar.show()
|
||||||
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_WIDTH - 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 - 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 _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(SIDEBAR_WIDTH, maxf(100.0, $HUDRoot.size.y - 52.0))
|
_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.position = Vector2($HUDRoot.size.x - SIDEBAR_WIDTH - 8 if _sidebar_open else $HUDRoot.size.x, 44)
|
_cockpit.scale = Vector2.ONE * 0.85
|
||||||
|
_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)
|
||||||
|
_layout_debug()
|
||||||
|
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x - 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
|
||||||
_layout_inventory()
|
_layout_inventory()
|
||||||
@ -116,7 +160,7 @@ func _layout_inventory() -> void:
|
|||||||
if _inventory_clip == null:
|
if _inventory_clip == null:
|
||||||
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(_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 - 8)))
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
_layout_inventory()
|
_layout_inventory()
|
||||||
@ -132,7 +176,7 @@ AKTUALNA REGENERACJA
|
|||||||
Energia: %.1f pkt/s
|
Energia: %.1f pkt/s
|
||||||
Tarcze: %.1f pkt/s
|
Tarcze: %.1f pkt/s
|
||||||
|
|
||||||
%s""" % [
|
%s""".replace("\r", "") % [
|
||||||
GameState.system_level,
|
GameState.system_level,
|
||||||
int(game.call("get_remaining_enemies")),
|
int(game.call("get_remaining_enemies")),
|
||||||
player.velocity.length(),
|
player.velocity.length(),
|
||||||
@ -143,7 +187,9 @@ Tarcze: %.1f pkt/s
|
|||||||
|
|
||||||
func _toggle_debug() -> void:
|
func _toggle_debug() -> void:
|
||||||
_debug_expanded = not _debug_expanded
|
_debug_expanded = not _debug_expanded
|
||||||
|
GameState.hud_panel_state["debug_expanded"] = _debug_expanded
|
||||||
debug_info.visible = _debug_expanded
|
debug_info.visible = _debug_expanded
|
||||||
|
_debug_scroll.visible = _debug_expanded
|
||||||
_update_debug_toggle()
|
_update_debug_toggle()
|
||||||
|
|
||||||
func _update_debug_toggle() -> void:
|
func _update_debug_toggle() -> void:
|
||||||
@ -178,7 +224,7 @@ Energia: %+.1f pkt
|
|||||||
Prędkość maks.: %+.1f%%
|
Prędkość maks.: %+.1f%%
|
||||||
Skrócenie cooldownu rakiet: %.2f s
|
Skrócenie cooldownu rakiet: %.2f s
|
||||||
Doświadczenie: %+.1f%%
|
Doświadczenie: %+.1f%%
|
||||||
Kredyty: %+.1f%%""" % [
|
Kredyty: %+.1f%%""".replace("\r", "") % [
|
||||||
(float(player.call("get_weapon_damage_multiplier")) - 1.0) * 100.0,
|
(float(player.call("get_weapon_damage_multiplier")) - 1.0) * 100.0,
|
||||||
float(player.call("get_critical_chance")) * 100.0,
|
float(player.call("get_critical_chance")) * 100.0,
|
||||||
float(player.get("critical_damage_bonus")) * 100.0,
|
float(player.get("critical_damage_bonus")) * 100.0,
|
||||||
@ -202,18 +248,18 @@ func _create_ability_bar() -> void:
|
|||||||
var panel := PanelContainer.new()
|
var panel := PanelContainer.new()
|
||||||
panel.name = "ActiveAbilities"
|
panel.name = "ActiveAbilities"
|
||||||
$HUDRoot.add_child(panel)
|
$HUDRoot.add_child(panel)
|
||||||
panel.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_LEFT)
|
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
|
||||||
panel.offset_left = 12.0
|
panel.offset_left = -300.0
|
||||||
panel.offset_right = 12.0
|
panel.offset_right = 300.0
|
||||||
panel.offset_top = -54.0
|
panel.offset_top = -188.0
|
||||||
panel.offset_bottom = -12.0
|
panel.offset_bottom = -146.0
|
||||||
_ability_bar = HBoxContainer.new()
|
_ability_bar = HBoxContainer.new()
|
||||||
_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 6:
|
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(120, 40)
|
button.custom_minimum_size = Vector2(110, 36)
|
||||||
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)
|
||||||
|
|||||||
@ -10,6 +10,8 @@ const WORLD_SIZE := SYSTEM_GENERATOR.WORLD_SIZE
|
|||||||
const SERVICE_APPROACH_DISTANCE := 180.0
|
const SERVICE_APPROACH_DISTANCE := 180.0
|
||||||
const WORMHOLE_PLANET_DISTANCE := 620.0
|
const WORMHOLE_PLANET_DISTANCE := 620.0
|
||||||
const WORMHOLE_ENTRY_RADIUS := 48.0
|
const WORMHOLE_ENTRY_RADIUS := 48.0
|
||||||
|
const BOSS_SPAWN_DISTANCE := 900.0
|
||||||
|
const BOSS_SPAWN_MARGIN := 160.0
|
||||||
const ENEMY_SCENE := preload("res://scenes/game/enemy_ship.tscn")
|
const ENEMY_SCENE := preload("res://scenes/game/enemy_ship.tscn")
|
||||||
const ENEMY_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES
|
const ENEMY_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES
|
||||||
|
|
||||||
@ -21,6 +23,8 @@ var services_menu: Control
|
|||||||
var system_cleared := false
|
var system_cleared := false
|
||||||
var wormhole: Node2D
|
var wormhole: Node2D
|
||||||
var _transitioning := false
|
var _transitioning := false
|
||||||
|
var _pending_boss: Dictionary = {}
|
||||||
|
var _boss_spawned := false
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
GameState.system_level = clampi(GameState.system_level, 1, LEVEL_BALANCE.MAX_LEVEL)
|
GameState.system_level = clampi(GameState.system_level, 1, LEVEL_BALANCE.MAX_LEVEL)
|
||||||
@ -85,12 +89,46 @@ func _spawn_celestial_bodies() -> void:
|
|||||||
|
|
||||||
func _spawn_enemies() -> void:
|
func _spawn_enemies() -> void:
|
||||||
for data in system_data["enemies"]:
|
for data in system_data["enemies"]:
|
||||||
var enemy := ENEMY_SCENE.instantiate() as CharacterBody2D
|
if int(data["tier"]) == 2:
|
||||||
enemy.position = data["position"]
|
_pending_boss = data.duplicate()
|
||||||
enemy.call("apply_level_settings", GameState.system_level, int(data["tier"]))
|
else:
|
||||||
add_child(enemy)
|
_spawn_enemy(data, data["position"])
|
||||||
var texture: Texture2D = ENEMY_TEXTURES[int(data["texture_index"])]
|
|
||||||
enemy.call("configure", player, texture)
|
func _spawn_enemy(data: Dictionary, spawn_position: Vector2) -> CharacterBody2D:
|
||||||
|
var enemy := ENEMY_SCENE.instantiate() as CharacterBody2D
|
||||||
|
enemy.position = spawn_position
|
||||||
|
enemy.call("apply_level_settings", GameState.system_level, int(data["tier"]))
|
||||||
|
add_child(enemy)
|
||||||
|
var texture: Texture2D = ENEMY_TEXTURES[int(data["texture_index"])]
|
||||||
|
enemy.call("configure", player, texture)
|
||||||
|
return enemy
|
||||||
|
|
||||||
|
func _spawn_boss() -> void:
|
||||||
|
if _boss_spawned or _pending_boss.is_empty():
|
||||||
|
return
|
||||||
|
_boss_spawned = true
|
||||||
|
_spawn_enemy(_pending_boss, _find_boss_spawn_position())
|
||||||
|
_pending_boss.clear()
|
||||||
|
|
||||||
|
func _find_boss_spawn_position() -> Vector2:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
rng.seed = GameState.system_seed ^ 0x424f5353
|
||||||
|
var angle := rng.randf_range(0.0, TAU)
|
||||||
|
for step in 64:
|
||||||
|
var candidate := player.global_position + Vector2.RIGHT.rotated(angle + TAU * step / 64.0) * BOSS_SPAWN_DISTANCE
|
||||||
|
if absf(candidate.x) > WORLD_SIZE.x * 0.5 - BOSS_SPAWN_MARGIN or absf(candidate.y) > WORLD_SIZE.y * 0.5 - BOSS_SPAWN_MARGIN:
|
||||||
|
continue
|
||||||
|
if candidate.length() < 300.0:
|
||||||
|
continue
|
||||||
|
var clear := true
|
||||||
|
for planet_data in system_data["planets"]:
|
||||||
|
if candidate.distance_to(planet_data["position"]) < float(planet_data["radius"]) + 130.0:
|
||||||
|
clear = false
|
||||||
|
break
|
||||||
|
if clear:
|
||||||
|
return candidate
|
||||||
|
# At the map edge, place the encounter toward the center.
|
||||||
|
return player.global_position + (-player.global_position).normalized() * BOSS_SPAWN_DISTANCE
|
||||||
|
|
||||||
func get_remaining_enemies() -> int:
|
func get_remaining_enemies() -> int:
|
||||||
var remaining := 0
|
var remaining := 0
|
||||||
@ -104,8 +142,11 @@ func _physics_process(_delta: float) -> void:
|
|||||||
services_menu.call("hide_services")
|
services_menu.call("hide_services")
|
||||||
return
|
return
|
||||||
if not system_cleared and get_remaining_enemies() == 0:
|
if not system_cleared and get_remaining_enemies() == 0:
|
||||||
system_cleared = true
|
if not _boss_spawned and not _pending_boss.is_empty():
|
||||||
protected_planet.call("set_safe", true)
|
_spawn_boss()
|
||||||
|
else:
|
||||||
|
system_cleared = true
|
||||||
|
protected_planet.call("set_safe", true)
|
||||||
if system_cleared and is_near_protected_planet():
|
if system_cleared and is_near_protected_planet():
|
||||||
if not services_menu.visible:
|
if not services_menu.visible:
|
||||||
services_menu.call("show_services", GameState.system_level >= LEVEL_BALANCE.MAX_LEVEL, is_instance_valid(wormhole))
|
services_menu.call("show_services", GameState.system_level >= LEVEL_BALANCE.MAX_LEVEL, is_instance_valid(wormhole))
|
||||||
|
|||||||
@ -8,6 +8,7 @@ var restart_inventory: Dictionary = {}
|
|||||||
var system_level: int = 1
|
var system_level: int = 1
|
||||||
var system_seed: int = 0
|
var system_seed: int = 0
|
||||||
var explored_pois: Dictionary = {}
|
var explored_pois: Dictionary = {}
|
||||||
|
var hud_panel_state: Dictionary = {}
|
||||||
|
|
||||||
func create_system_seed() -> int:
|
func create_system_seed() -> int:
|
||||||
var rng := RandomNumberGenerator.new()
|
var rng := RandomNumberGenerator.new()
|
||||||
@ -20,6 +21,7 @@ func start_new_run() -> void:
|
|||||||
system_seed = create_system_seed()
|
system_seed = create_system_seed()
|
||||||
restart_inventory.clear()
|
restart_inventory.clear()
|
||||||
explored_pois.clear()
|
explored_pois.clear()
|
||||||
|
hud_panel_state.clear()
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var game_window := get_tree().root
|
var game_window := get_tree().root
|
||||||
|
|||||||
@ -21,6 +21,8 @@ const MINI_BOOST_ENERGY_PER_SECOND := 20.0
|
|||||||
|
|
||||||
@export var base_max_hull := 100.0
|
@export var base_max_hull := 100.0
|
||||||
@export var base_max_shields := 100.0
|
@export var base_max_shields := 100.0
|
||||||
|
@export var base_scanner_range := 1000.0
|
||||||
|
var scanner_range := 1000.0
|
||||||
@export var base_max_energy := 100.0
|
@export var base_max_energy := 100.0
|
||||||
@export var base_max_speed := 90.0
|
@export var base_max_speed := 90.0
|
||||||
@export var base_energy_regeneration := 5.0
|
@export var base_energy_regeneration := 5.0
|
||||||
@ -69,6 +71,7 @@ func _enter_tree() -> void:
|
|||||||
func apply_equipment_bonuses(bonuses: Dictionary) -> void:
|
func apply_equipment_bonuses(bonuses: Dictionary) -> void:
|
||||||
max_hull = (base_max_hull + float(bonuses.get("max_hull", 0.0))) * (1.0 + float(bonuses.get("hull_percent", 0.0)) / 100.0)
|
max_hull = (base_max_hull + float(bonuses.get("max_hull", 0.0))) * (1.0 + float(bonuses.get("hull_percent", 0.0)) / 100.0)
|
||||||
max_shields = (base_max_shields + float(bonuses.get("max_shields", 0.0))) * (1.0 + float(bonuses.get("shield_percent", 0.0)) / 100.0)
|
max_shields = (base_max_shields + float(bonuses.get("max_shields", 0.0))) * (1.0 + float(bonuses.get("shield_percent", 0.0)) / 100.0)
|
||||||
|
scanner_range = base_scanner_range + float(bonuses.get("scanner_range", 0.0))
|
||||||
max_energy = base_max_energy + float(bonuses.get("max_energy", 0.0))
|
max_energy = base_max_energy + float(bonuses.get("max_energy", 0.0))
|
||||||
max_speed = (base_max_speed + float(bonuses.get("max_speed", 0.0))) * (1.0 + float(bonuses.get("speed_percent", 0.0)) / 100.0)
|
max_speed = (base_max_speed + float(bonuses.get("max_speed", 0.0))) * (1.0 + float(bonuses.get("speed_percent", 0.0)) / 100.0)
|
||||||
damage_multiplier = 1.0 + float(bonuses.get("damage_percent", 0.0)) / 100.0
|
damage_multiplier = 1.0 + float(bonuses.get("damage_percent", 0.0)) / 100.0
|
||||||
@ -87,7 +90,7 @@ func apply_equipment_bonuses(bonuses: Dictionary) -> void:
|
|||||||
_update_shield_visual()
|
_update_shield_visual()
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
for index in 6:
|
for index in ShipInventory.EXTENSION_SLOT_COUNT:
|
||||||
_ensure_input_action(StringName("ability_%d" % (index + 1)), (KEY_1 + index) as Key)
|
_ensure_input_action(StringName("ability_%d" % (index + 1)), (KEY_1 + index) as Key)
|
||||||
_ensure_input_action(&"ship_thrust", KEY_W)
|
_ensure_input_action(&"ship_thrust", KEY_W)
|
||||||
_ensure_input_action(&"ship_mini_boost", KEY_TAB)
|
_ensure_input_action(&"ship_mini_boost", KEY_TAB)
|
||||||
@ -97,6 +100,15 @@ func _ready() -> void:
|
|||||||
_ensure_input_action(&"ship_strafe_left", KEY_Q)
|
_ensure_input_action(&"ship_strafe_left", KEY_Q)
|
||||||
_ensure_input_action(&"ship_strafe_right", KEY_E)
|
_ensure_input_action(&"ship_strafe_right", KEY_E)
|
||||||
|
|
||||||
|
var scanner_layer := CanvasLayer.new()
|
||||||
|
scanner_layer.name = "ScannerOverlay"
|
||||||
|
scanner_layer.layer = 8
|
||||||
|
add_child(scanner_layer)
|
||||||
|
var scanner := Control.new()
|
||||||
|
scanner.set_script(preload("res://scripts/ui/scanner_overlay.gd"))
|
||||||
|
scanner.set("player", self)
|
||||||
|
scanner_layer.add_child(scanner)
|
||||||
|
scanner.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
_sprite = $Sprite2D
|
_sprite = $Sprite2D
|
||||||
var texture_path := SHIP_CATALOG.texture_path(SHIP_CATALOG.for_path(GameState.selected_ship_path))
|
var texture_path := SHIP_CATALOG.texture_path(SHIP_CATALOG.for_path(GameState.selected_ship_path))
|
||||||
if texture_path.is_empty() or not ResourceLoader.exists(texture_path):
|
if texture_path.is_empty() or not ResourceLoader.exists(texture_path):
|
||||||
@ -339,7 +351,7 @@ func start_boost(speed_bonus: float, acceleration_time: float) -> void:
|
|||||||
_boost_velocity_acceleration = (max_speed + _boost_target) / maxf(0.01, acceleration_time)
|
_boost_velocity_acceleration = (max_speed + _boost_target) / maxf(0.01, acceleration_time)
|
||||||
|
|
||||||
func get_active_ability(slot_index: int) -> ActiveAbility:
|
func get_active_ability(slot_index: int) -> ActiveAbility:
|
||||||
var item: ItemInstance = $ShipInventory.get_item("module", slot_index)
|
var item: ItemInstance = $ShipInventory.get_item("extension", slot_index)
|
||||||
return item.definition.active_ability if item != null and item.definition != null else null
|
return item.definition.active_ability if item != null and item.definition != null else null
|
||||||
|
|
||||||
func ability_unavailable_reason(slot_index: int) -> String:
|
func ability_unavailable_reason(slot_index: int) -> String:
|
||||||
@ -357,7 +369,7 @@ func activate_ability(slot_index: int) -> bool:
|
|||||||
func _unhandled_key_input(event: InputEvent) -> void:
|
func _unhandled_key_input(event: InputEvent) -> void:
|
||||||
if event is InputEventKey and event.echo:
|
if event is InputEventKey and event.echo:
|
||||||
return
|
return
|
||||||
for index in 6:
|
for index in ShipInventory.EXTENSION_SLOT_COUNT:
|
||||||
if event.is_action_pressed("ability_%d" % (index + 1)):
|
if event.is_action_pressed("ability_%d" % (index + 1)):
|
||||||
activate_ability(index)
|
activate_ability(index)
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|||||||
@ -8,21 +8,20 @@ const RAY_COLLISION_MASK := 13 # World, enemies, and the weapon test target.
|
|||||||
@onready var ship: CharacterBody2D = get_parent()
|
@onready var ship: CharacterBody2D = get_parent()
|
||||||
@onready var inventory: ShipInventory = ship.get_node("ShipInventory")
|
@onready var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||||
|
|
||||||
var _shot_timers := [0.0, 0.0]
|
var _shot_timers := [0.0, 0.0, 0.0]
|
||||||
var _laser_pulse_timers := [0.0, 0.0]
|
var _laser_pulse_timers := [0.0, 0.0, 0.0]
|
||||||
var _laser_lines: Array[Line2D] = []
|
var _laser_lines: Array[Line2D] = []
|
||||||
var _fire_buttons_down := [false, false]
|
var _fire_buttons_down := [false, false, false]
|
||||||
var _fire_just_pressed := [false, false]
|
var _fire_just_pressed := [false, false, false]
|
||||||
var _drag_fire_blocked := false
|
var _drag_fire_blocked := false
|
||||||
var missile_cooldown_remaining := 0.0
|
var missile_cooldown_remaining := 0.0
|
||||||
var missile_cooldown_duration := 5.0
|
var missile_cooldown_duration := 5.0
|
||||||
var _missile_just_pressed := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_ensure_input_action(&"ship_fire_primary", MOUSE_BUTTON_LEFT)
|
_ensure_input_action(&"ship_fire_primary", MOUSE_BUTTON_LEFT)
|
||||||
_ensure_input_action(&"ship_fire_secondary", MOUSE_BUTTON_RIGHT)
|
_ensure_input_action(&"ship_fire_secondary", MOUSE_BUTTON_RIGHT)
|
||||||
_ensure_input_action(&"ship_fire_missile", MOUSE_BUTTON_MIDDLE)
|
_ensure_input_action(&"ship_fire_missile", MOUSE_BUTTON_MIDDLE)
|
||||||
for slot_index in 2:
|
for slot_index in ShipInventory.WEAPON_SLOT_COUNT:
|
||||||
var beam := Line2D.new()
|
var beam := Line2D.new()
|
||||||
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)
|
||||||
@ -46,8 +45,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
return
|
return
|
||||||
var slot_index := -1
|
var slot_index := -1
|
||||||
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
||||||
_missile_just_pressed = event.pressed
|
slot_index = 2
|
||||||
return
|
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
slot_index = 0
|
slot_index = 0
|
||||||
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
||||||
@ -63,30 +61,25 @@ func _physics_process(delta: float) -> void:
|
|||||||
if ship.get_viewport().gui_is_dragging():
|
if ship.get_viewport().gui_is_dragging():
|
||||||
_drag_fire_blocked = true
|
_drag_fire_blocked = true
|
||||||
if _drag_fire_blocked:
|
if _drag_fire_blocked:
|
||||||
_missile_just_pressed = false
|
for index in ShipInventory.WEAPON_SLOT_COUNT:
|
||||||
for index in 2:
|
|
||||||
_fire_buttons_down[index] = false
|
_fire_buttons_down[index] = false
|
||||||
_fire_just_pressed[index] = false
|
_fire_just_pressed[index] = false
|
||||||
_laser_pulse_timers[index] = 0.0
|
_laser_pulse_timers[index] = 0.0
|
||||||
_laser_lines[index].visible = false
|
_laser_lines[index].visible = false
|
||||||
_shot_timers[index] = maxf(0.0, _shot_timers[index] - delta)
|
_shot_timers[index] = maxf(0.0, _shot_timers[index] - delta)
|
||||||
# Require release after dropping, so the drag gesture cannot become a shot.
|
# Require release after dropping, so the drag gesture cannot become a shot.
|
||||||
if not ship.get_viewport().gui_is_dragging() and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
|
if not ship.get_viewport().gui_is_dragging() and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) and not Input.is_mouse_button_pressed(MOUSE_BUTTON_MIDDLE):
|
||||||
_drag_fire_blocked = false
|
_drag_fire_blocked = false
|
||||||
return
|
return
|
||||||
if bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
if bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
||||||
_missile_just_pressed = false
|
|
||||||
for line in _laser_lines:
|
for line in _laser_lines:
|
||||||
line.visible = false
|
line.visible = false
|
||||||
return
|
return
|
||||||
var mouse_over_ui := ship.get_viewport().gui_get_hovered_control() != null
|
var mouse_over_ui := ship.get_viewport().gui_get_hovered_control() != null
|
||||||
if not mouse_over_ui and (Input.is_action_just_pressed("ship_fire_missile") or _missile_just_pressed):
|
for slot_index in ShipInventory.WEAPON_SLOT_COUNT:
|
||||||
try_fire_missile()
|
|
||||||
_missile_just_pressed = false
|
|
||||||
for slot_index in 2:
|
|
||||||
_shot_timers[slot_index] = maxf(0.0, _shot_timers[slot_index] - delta)
|
_shot_timers[slot_index] = maxf(0.0, _shot_timers[slot_index] - delta)
|
||||||
_laser_pulse_timers[slot_index] = maxf(0.0, _laser_pulse_timers[slot_index] - delta)
|
_laser_pulse_timers[slot_index] = maxf(0.0, _laser_pulse_timers[slot_index] - delta)
|
||||||
var action_name := "ship_fire_primary" if slot_index == 0 else "ship_fire_secondary"
|
var action_name: String = ["ship_fire_primary", "ship_fire_secondary", "ship_fire_missile"][slot_index]
|
||||||
var is_pressed: bool = not mouse_over_ui and (
|
var is_pressed: bool = not mouse_over_ui and (
|
||||||
Input.is_action_pressed(action_name) or _fire_buttons_down[slot_index]
|
Input.is_action_pressed(action_name) or _fire_buttons_down[slot_index]
|
||||||
)
|
)
|
||||||
@ -112,18 +105,19 @@ func _physics_process(delta: float) -> void:
|
|||||||
_laser_lines[slot_index].visible = _laser_pulse_timers[slot_index] > 0.0
|
_laser_lines[slot_index].visible = _laser_pulse_timers[slot_index] > 0.0
|
||||||
_fire_laser(slot_index, item)
|
_fire_laser(slot_index, item)
|
||||||
ItemDefinition.WeaponKind.MISSILE:
|
ItemDefinition.WeaponKind.MISSILE:
|
||||||
pass # Rockets fire exclusively from slot 3.
|
if is_just_pressed:
|
||||||
|
try_fire_missile(slot_index)
|
||||||
_:
|
_:
|
||||||
if _shot_timers[slot_index] <= 0.0 and _consume_shot_resource(item):
|
if _shot_timers[slot_index] <= 0.0 and _consume_shot_resource(item):
|
||||||
_fire_projectile(item)
|
_fire_projectile(item)
|
||||||
_shot_timers[slot_index] = definition.fire_interval
|
_shot_timers[slot_index] = definition.fire_interval
|
||||||
for slot_index in 2:
|
for slot_index in ShipInventory.WEAPON_SLOT_COUNT:
|
||||||
_fire_just_pressed[slot_index] = false
|
_fire_just_pressed[slot_index] = false
|
||||||
|
|
||||||
func try_fire_missile() -> bool:
|
func try_fire_missile(slot_index: int = 2) -> bool:
|
||||||
if missile_cooldown_remaining > 0.0 or bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
if missile_cooldown_remaining > 0.0 or bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
||||||
return false
|
return false
|
||||||
var item := inventory.get_item("weapon", ShipInventory.MISSILE_SLOT)
|
var item := inventory.get_item("weapon", slot_index)
|
||||||
if item == null or item.definition.weapon_kind != ItemDefinition.WeaponKind.MISSILE:
|
if item == null or item.definition.weapon_kind != ItemDefinition.WeaponKind.MISSILE:
|
||||||
return false
|
return false
|
||||||
if inventory.missile_ammunition <= 0:
|
if inventory.missile_ammunition <= 0:
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class_name ItemAffixDefinition
|
|||||||
@export_range(0.0, 1000.0, 0.1) var selection_weight: float = 1.0
|
@export_range(0.0, 1000.0, 0.1) var selection_weight: float = 1.0
|
||||||
|
|
||||||
@export_group("Dozwolone przedmioty")
|
@export_group("Dozwolone przedmioty")
|
||||||
@export_flags("Weapon", "Shield", "Hull", "Generator", "Extension", "Active extension") var category_mask: int = 63
|
@export_flags("Weapon", "Shield", "Hull", "Reactor", "Engine", "Active extension", "Computer") var category_mask: int = 95
|
||||||
# Empty means every item in the allowed categories.
|
# Empty means every item in the allowed categories.
|
||||||
@export var allowed_item_ids: PackedStringArray = PackedStringArray()
|
@export var allowed_item_ids: PackedStringArray = PackedStringArray()
|
||||||
@export var excluded_item_ids: PackedStringArray = PackedStringArray()
|
@export var excluded_item_ids: PackedStringArray = PackedStringArray()
|
||||||
@ -32,6 +32,7 @@ func can_roll(item: ItemDefinition, level: int) -> bool:
|
|||||||
return (
|
return (
|
||||||
enabled and selection_weight > 0.0 and not affix_id.is_empty()
|
enabled and selection_weight > 0.0 and not affix_id.is_empty()
|
||||||
and not stat_key.is_empty() and item != null
|
and not stat_key.is_empty() and item != null
|
||||||
|
and item.category != ItemDefinition.Category.ACTIVE_EXTENSION
|
||||||
and level >= minimum_level and level <= maximum_level
|
and level >= minimum_level and level <= maximum_level
|
||||||
and (category_mask & (1 << item.category)) != 0
|
and (category_mask & (1 << item.category)) != 0
|
||||||
and (allowed_item_ids.is_empty() or item.item_id in allowed_item_ids)
|
and (allowed_item_ids.is_empty() or item.item_id in allowed_item_ids)
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
extends Resource
|
extends Resource
|
||||||
class_name ItemDefinition
|
class_name ItemDefinition
|
||||||
|
|
||||||
enum Category { WEAPON, SHIELD, HULL, GENERATOR, EXTENSION, ACTIVE_EXTENSION }
|
enum Category { WEAPON, SHIELD, ARMOR, REACTOR, ENGINE, ACTIVE_EXTENSION, COMPUTER }
|
||||||
enum WeaponKind { PLASMA, MACHINE_GUN, LASER, MISSILE }
|
enum WeaponKind { PLASMA, MACHINE_GUN, LASER, MISSILE }
|
||||||
|
|
||||||
@export var item_id: String = ""
|
@export var item_id: String = ""
|
||||||
@export var display_name: String = ""
|
@export var display_name: String = ""
|
||||||
@export var category: Category = Category.EXTENSION
|
@export var icon: Texture2D
|
||||||
|
@export var category: Category = Category.ENGINE
|
||||||
@export_multiline var description: String = ""
|
@export_multiline var description: String = ""
|
||||||
@export var primary_stat: String = ""
|
@export var primary_stat: String = ""
|
||||||
@export var primary_value: float = 0.0
|
@export var primary_value: float = 0.0
|
||||||
|
|||||||
@ -14,7 +14,7 @@ const DEFINITIONS := [
|
|||||||
preload("res://resources/items/afterburner.tres"),
|
preload("res://resources/items/afterburner.tres"),
|
||||||
preload("res://resources/items/shield_charge.tres"),
|
preload("res://resources/items/shield_charge.tres"),
|
||||||
preload("res://resources/items/repair_drones.tres"),
|
preload("res://resources/items/repair_drones.tres"),
|
||||||
preload("res://resources/items/scanner.tres"),
|
preload("res://resources/items/ship_computer.tres"),
|
||||||
]
|
]
|
||||||
const AFFIX_DATABASE := preload("res://resources/items/affix_database.tres")
|
const AFFIX_DATABASE := preload("res://resources/items/affix_database.tres")
|
||||||
|
|
||||||
@ -36,6 +36,8 @@ static func generate_for_definition(definition: ItemDefinition, level: int, enem
|
|||||||
item.damage_max = maxf(item.damage_min + 1.0, roundf((lower + spread) * scale_factor))
|
item.damage_max = maxf(item.damage_min + 1.0, roundf((lower + spread) * scale_factor))
|
||||||
item.primary_value_override = (item.damage_min + item.damage_max) * 0.5
|
item.primary_value_override = (item.damage_min + item.damage_max) * 0.5
|
||||||
item.energy_regeneration_override = item.definition.energy_regeneration_bonus * scale_factor * randf_range(0.8, 1.2)
|
item.energy_regeneration_override = item.definition.energy_regeneration_bonus * scale_factor * randf_range(0.8, 1.2)
|
||||||
|
if definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
|
return item
|
||||||
var roll := randf()
|
var roll := randf()
|
||||||
var count := 1 if roll < 0.5 else (2 if roll < 0.75 else (3 if roll < 0.89 else (4 if roll < 0.97 else 5)))
|
var count := 1 if roll < 0.5 else (2 if roll < 0.75 else (3 if roll < 0.89 else (4 if roll < 0.97 else 5)))
|
||||||
if enemy_tier == 1:
|
if enemy_tier == 1:
|
||||||
|
|||||||
@ -116,7 +116,7 @@ func get_tooltip_text() -> String:
|
|||||||
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||||
lines.append("Zasięg: %.0f px • Amunicja: 1 / strzał" % definition.weapon_range)
|
lines.append("Zasięg: %.0f px • Amunicja: 1 / strzał" % definition.weapon_range)
|
||||||
elif definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
elif definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||||
lines.append("ŚPM • Amunicja: 1 rakieta / strzał • Cooldown bazowy: 5 s • Bez kosztu energii")
|
lines.append("Amunicja: 1 rakieta / strzał • Cooldown bazowy: 5 s • Bez kosztu energii")
|
||||||
else:
|
else:
|
||||||
lines.append("Zasięg: %.0f px • Energia: %.1f / strzał" % [definition.weapon_range, get_energy_cost()])
|
lines.append("Zasięg: %.0f px • Energia: %.1f / strzał" % [definition.weapon_range, get_energy_cost()])
|
||||||
lines.append("Odstęp strzałów: %.2f s" % maxf(definition.fire_interval, definition.weapon_cooldown))
|
lines.append("Odstęp strzałów: %.2f s" % maxf(definition.fire_interval, definition.weapon_cooldown))
|
||||||
@ -129,4 +129,4 @@ func get_tooltip_text() -> String:
|
|||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
static func stat_name(key: String) -> String:
|
static func stat_name(key: String) -> String:
|
||||||
return str({"shield_on_damage_percent": "Odzysk tarcz z obrażeń", "damage": "Obrażenia", "max_hull": "Kadłub", "max_shields": "Tarcze", "max_energy": "Energia", "max_speed": "Prędkość", "energy_regeneration": "Regeneracja energii", "shield_regeneration": "Regeneracja tarcz", "hull_percent": "Kadłub", "shield_percent": "Tarcze", "damage_percent": "Obrażenia broni", "speed_percent": "Prędkość statku", "experience_percent": "Doświadczenie (EXP)", "credits_percent": "Kredyty", "critical_chance_percent": "Szansa na trafienie krytyczne", "critical_damage_percent": "Obrażenia krytyczne"}.get(key, key))
|
return str({"missile_cooldown_reduction": "Skrócenie cooldownu rakiet", "scanner_range": "Zasięg skanera", "shield_on_damage_percent": "Odzysk tarcz z obrażeń", "damage": "Obrażenia", "max_hull": "Kadłub", "max_shields": "Tarcze", "max_energy": "Energia", "max_speed": "Prędkość", "energy_regeneration": "Regeneracja energii", "shield_regeneration": "Regeneracja tarcz", "hull_percent": "Kadłub", "shield_percent": "Tarcze", "damage_percent": "Obrażenia broni", "speed_percent": "Prędkość statku", "experience_percent": "Doświadczenie (EXP)", "credits_percent": "Kredyty", "critical_chance_percent": "Szansa na trafienie krytyczne", "critical_damage_percent": "Obrażenia krytyczne"}.get(key, key))
|
||||||
|
|||||||
@ -6,12 +6,14 @@ signal ammunition_changed
|
|||||||
|
|
||||||
const CARGO_SIZE := 20
|
const CARGO_SIZE := 20
|
||||||
const WEAPON_SLOT_COUNT := 3
|
const WEAPON_SLOT_COUNT := 3
|
||||||
const MISSILE_SLOT := 2
|
|
||||||
const STARTING_MISSILE_AMMUNITION := 2
|
const STARTING_MISSILE_AMMUNITION := 2
|
||||||
const MISSILE_CRAFT_PARTS_COST := 50.0
|
const MISSILE_CRAFT_PARTS_COST := 50.0
|
||||||
const MISSILE_BUY_BASE_COST := 10
|
const MISSILE_BUY_BASE_COST := 10
|
||||||
const MISSILE_DEFINITIONS := [preload("res://resources/items/missile_launcher.tres"), preload("res://resources/items/unguided_missile.tres")]
|
const MISSILE_DEFINITIONS := [preload("res://resources/items/missile_launcher.tres"), preload("res://resources/items/unguided_missile.tres")]
|
||||||
const MODULE_SLOT_COUNT := 6
|
const MODULE_SLOT_COUNT := 5
|
||||||
|
const EXTENSION_SLOT_COUNT := 5
|
||||||
|
const MODULE_CATEGORIES := [ItemDefinition.Category.SHIELD, ItemDefinition.Category.ARMOR, ItemDefinition.Category.ENGINE, ItemDefinition.Category.REACTOR, ItemDefinition.Category.COMPUTER]
|
||||||
|
const MODULE_NAMES := ["Tarcze", "Pancerz", "Silnik", "Reaktor", "Komputer"]
|
||||||
const STARTING_AMMUNITION := 50
|
const STARTING_AMMUNITION := 50
|
||||||
const AMMUNITION_CRAFT_AMOUNT := 100
|
const AMMUNITION_CRAFT_AMOUNT := 100
|
||||||
const AMMUNITION_CRAFT_PARTS_COST := 50.0
|
const AMMUNITION_CRAFT_PARTS_COST := 50.0
|
||||||
@ -24,6 +26,7 @@ var missile_ammunition: int = STARTING_MISSILE_AMMUNITION
|
|||||||
var cargo: Array[ItemInstance] = []
|
var cargo: Array[ItemInstance] = []
|
||||||
var weapon_slots: Array[ItemInstance] = []
|
var weapon_slots: Array[ItemInstance] = []
|
||||||
var module_slots: Array[ItemInstance] = []
|
var module_slots: Array[ItemInstance] = []
|
||||||
|
var extension_slots: Array[ItemInstance] = []
|
||||||
|
|
||||||
@onready var ship: CharacterBody2D = get_parent()
|
@onready var ship: CharacterBody2D = get_parent()
|
||||||
|
|
||||||
@ -32,16 +35,18 @@ func _ready() -> void:
|
|||||||
cargo.resize(CARGO_SIZE)
|
cargo.resize(CARGO_SIZE)
|
||||||
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
||||||
module_slots.resize(MODULE_SLOT_COUNT)
|
module_slots.resize(MODULE_SLOT_COUNT)
|
||||||
|
extension_slots.resize(EXTENSION_SLOT_COUNT)
|
||||||
if GameState.restart_inventory.is_empty():
|
if GameState.restart_inventory.is_empty():
|
||||||
_add_starter_items()
|
_add_starter_items()
|
||||||
else:
|
else:
|
||||||
cargo.assign(GameState.restart_inventory["cargo"])
|
cargo.assign(GameState.restart_inventory["cargo"])
|
||||||
weapon_slots.assign(GameState.restart_inventory["weapon"])
|
weapon_slots.assign(GameState.restart_inventory["weapon"])
|
||||||
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
||||||
module_slots.assign(GameState.restart_inventory["module"])
|
_restore_modules(GameState.restart_inventory)
|
||||||
ammunition = int(GameState.restart_inventory.get("ammunition", STARTING_AMMUNITION))
|
ammunition = int(GameState.restart_inventory.get("ammunition", STARTING_AMMUNITION))
|
||||||
missile_ammunition = int(GameState.restart_inventory.get("missile_ammunition", STARTING_MISSILE_AMMUNITION))
|
missile_ammunition = int(GameState.restart_inventory.get("missile_ammunition", STARTING_MISSILE_AMMUNITION))
|
||||||
GameState.restart_inventory.clear()
|
GameState.restart_inventory.clear()
|
||||||
|
_remove_extension_addons()
|
||||||
_recalculate_ship_stats()
|
_recalculate_ship_stats()
|
||||||
inventory_changed.emit()
|
inventory_changed.emit()
|
||||||
|
|
||||||
@ -58,6 +63,7 @@ func preserve_for_restart() -> void:
|
|||||||
"cargo": cargo.duplicate(),
|
"cargo": cargo.duplicate(),
|
||||||
"weapon": weapon_slots.duplicate(),
|
"weapon": weapon_slots.duplicate(),
|
||||||
"module": module_slots.duplicate(),
|
"module": module_slots.duplicate(),
|
||||||
|
"extension": extension_slots.duplicate(),
|
||||||
"ammunition": ammunition,
|
"ammunition": ammunition,
|
||||||
"missile_ammunition": missile_ammunition,
|
"missile_ammunition": missile_ammunition,
|
||||||
}
|
}
|
||||||
@ -105,6 +111,9 @@ func buy_ammunition() -> bool:
|
|||||||
func add_item(item: ItemInstance) -> bool:
|
func add_item(item: ItemInstance) -> bool:
|
||||||
if item == null or item.definition == null:
|
if item == null or item.definition == null:
|
||||||
return false
|
return false
|
||||||
|
if item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
|
item.additional_modifiers.clear()
|
||||||
|
item.rarity = 0
|
||||||
for index in cargo.size():
|
for index in cargo.size():
|
||||||
if cargo[index] == null:
|
if cargo[index] == null:
|
||||||
cargo[index] = item
|
cargo[index] = item
|
||||||
@ -141,8 +150,12 @@ func can_move_item(from_kind: String, from_index: int, to_kind: String, to_index
|
|||||||
|
|
||||||
func _accepts_item(kind: String, index: int, item: ItemInstance) -> bool:
|
func _accepts_item(kind: String, index: int, item: ItemInstance) -> bool:
|
||||||
if kind == "weapon":
|
if kind == "weapon":
|
||||||
return item.definition.category == ItemDefinition.Category.WEAPON and (item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE) == (index == MISSILE_SLOT)
|
return item.definition.category == ItemDefinition.Category.WEAPON
|
||||||
return kind != "module" or item.definition.category != ItemDefinition.Category.WEAPON
|
if kind == "module":
|
||||||
|
return item.definition.category == MODULE_CATEGORIES[index]
|
||||||
|
if kind == "extension":
|
||||||
|
return item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION and item.definition.active_ability != null
|
||||||
|
return kind == "cargo"
|
||||||
|
|
||||||
func get_missile_count() -> int:
|
func get_missile_count() -> int:
|
||||||
return missile_ammunition
|
return missile_ammunition
|
||||||
@ -196,6 +209,7 @@ func move_item(from_kind: String, from_index: int, to_kind: String, to_index: in
|
|||||||
var displaced := destination[to_index]
|
var displaced := destination[to_index]
|
||||||
destination[to_index] = source[from_index]
|
destination[to_index] = source[from_index]
|
||||||
source[from_index] = displaced
|
source[from_index] = displaced
|
||||||
|
_remove_extension_addons()
|
||||||
_recalculate_ship_stats()
|
_recalculate_ship_stats()
|
||||||
inventory_changed.emit()
|
inventory_changed.emit()
|
||||||
return true
|
return true
|
||||||
@ -208,6 +222,8 @@ func _get_slots(slot_kind: String) -> Array[ItemInstance]:
|
|||||||
return weapon_slots
|
return weapon_slots
|
||||||
"module":
|
"module":
|
||||||
return module_slots
|
return module_slots
|
||||||
|
"extension":
|
||||||
|
return extension_slots
|
||||||
return []
|
return []
|
||||||
|
|
||||||
func _recalculate_ship_stats() -> void:
|
func _recalculate_ship_stats() -> void:
|
||||||
@ -215,7 +231,7 @@ func _recalculate_ship_stats() -> void:
|
|||||||
for item in weapon_slots + module_slots:
|
for item in weapon_slots + module_slots:
|
||||||
if item == null or item.definition == null:
|
if item == null or item.definition == null:
|
||||||
continue
|
continue
|
||||||
for stat_key in ["max_hull", "max_shields", "max_energy", "max_speed", "energy_regeneration", "shield_regeneration", "hull_percent", "shield_percent", "damage_percent", "speed_percent", "experience_percent", "credits_percent", "critical_chance_percent", "critical_damage_percent"]:
|
for stat_key in ["shield_on_damage_percent", "scanner_range", "max_hull", "max_shields", "max_energy", "max_speed", "energy_regeneration", "shield_regeneration", "hull_percent", "shield_percent", "damage_percent", "speed_percent", "experience_percent", "credits_percent", "critical_chance_percent", "critical_damage_percent"]:
|
||||||
bonuses[stat_key] = float(bonuses.get(stat_key, 0.0)) + item.get_stat_total(stat_key)
|
bonuses[stat_key] = float(bonuses.get(stat_key, 0.0)) + item.get_stat_total(stat_key)
|
||||||
ship.call("apply_equipment_bonuses", bonuses)
|
ship.call("apply_equipment_bonuses", bonuses)
|
||||||
|
|
||||||
@ -228,3 +244,80 @@ func _add_starter_items() -> void:
|
|||||||
item.definition = definition
|
item.definition = definition
|
||||||
item.item_level = 1
|
item.item_level = 1
|
||||||
weapon_slots[0] = item
|
weapon_slots[0] = item
|
||||||
|
|
||||||
|
func _remove_extension_addons() -> void:
|
||||||
|
for item in cargo + extension_slots:
|
||||||
|
if item != null and item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
|
item.additional_modifiers.clear()
|
||||||
|
item.rarity = 0
|
||||||
|
|
||||||
|
func _restore_modules(saved: Dictionary) -> void:
|
||||||
|
if saved.has("extension"):
|
||||||
|
extension_slots.assign(saved["extension"])
|
||||||
|
extension_slots.resize(EXTENSION_SLOT_COUNT)
|
||||||
|
for item in saved.get("module", []):
|
||||||
|
if item == null or item.definition == null:
|
||||||
|
continue
|
||||||
|
var index := MODULE_CATEGORIES.find(item.definition.category)
|
||||||
|
if index >= 0 and module_slots[index] == null:
|
||||||
|
module_slots[index] = item
|
||||||
|
elif item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION and extension_slots.has(null):
|
||||||
|
extension_slots[extension_slots.find(null)] = item
|
||||||
|
else:
|
||||||
|
add_item(item)
|
||||||
|
|
||||||
|
func get_item_comparison(item: ItemInstance, equipped: ItemInstance) -> Array[Dictionary]:
|
||||||
|
var before := _comparison_stats(_comparison_bonuses())
|
||||||
|
var after := _comparison_stats(_comparison_bonuses(item, equipped))
|
||||||
|
var rows: Array[Dictionary] = []
|
||||||
|
for key in before:
|
||||||
|
var difference: float = float(after[key]["value"]) - float(before[key]["value"])
|
||||||
|
if is_zero_approx(difference):
|
||||||
|
continue
|
||||||
|
rows.append({"key": key, "name": before[key]["name"], "delta": difference, "unit": before[key]["unit"]})
|
||||||
|
return rows
|
||||||
|
|
||||||
|
func _comparison_bonuses(incoming: ItemInstance = null, outgoing: ItemInstance = null) -> Dictionary:
|
||||||
|
var bonuses := {}
|
||||||
|
for item in weapon_slots + module_slots:
|
||||||
|
if item == null or item == outgoing:
|
||||||
|
continue
|
||||||
|
_add_comparison_bonuses(bonuses, item)
|
||||||
|
if incoming != null:
|
||||||
|
_add_comparison_bonuses(bonuses, incoming)
|
||||||
|
return bonuses
|
||||||
|
|
||||||
|
func _add_comparison_bonuses(bonuses: Dictionary, item: ItemInstance) -> void:
|
||||||
|
for key in ["max_hull", "max_shields", "max_energy", "max_speed", "scanner_range", "hull_percent", "shield_percent", "speed_percent", "damage_percent", "critical_damage_percent", "critical_chance_percent", "shield_on_damage_percent", "energy_regeneration", "shield_regeneration", "missile_cooldown_reduction", "experience_percent", "credits_percent"]:
|
||||||
|
bonuses[key] = float(bonuses.get(key, 0.0)) + item.get_stat_total(key)
|
||||||
|
|
||||||
|
func _comparison_stats(bonuses: Dictionary) -> Dictionary:
|
||||||
|
var stats := {}
|
||||||
|
for data in [["max_hull", "base_max_hull", "hull_percent", "Pancerz", "pkt"], ["max_shields", "base_max_shields", "shield_percent", "Tarcze", "pkt"], ["max_speed", "base_max_speed", "speed_percent", "Prędkość", "px/s"]]:
|
||||||
|
var value := (float(ship.get(data[1])) + float(bonuses.get(data[0], 0.0))) * (1.0 + float(bonuses.get(data[2], 0.0)) / 100.0)
|
||||||
|
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"]]:
|
||||||
|
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")
|
||||||
|
var damage_factor := (1.0 + float(bonuses.get("damage_percent", 0.0)) / 100.0) * captain_damage
|
||||||
|
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))
|
||||||
|
for index in weapon_slots.size():
|
||||||
|
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
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
extends StaticBody2D
|
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 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 := ""
|
||||||
@ -14,6 +15,8 @@ var _label: Label
|
|||||||
var _rng := RandomNumberGenerator.new()
|
var _rng := RandomNumberGenerator.new()
|
||||||
var _mineral := "iron"
|
var _mineral := "iron"
|
||||||
var _points := PackedVector2Array()
|
var _points := PackedVector2Array()
|
||||||
|
var _asteroid_sprite: Sprite2D
|
||||||
|
var _asteroid_spin := 0.0
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
add_to_group("exploration_pois")
|
add_to_group("exploration_pois")
|
||||||
@ -30,6 +33,14 @@ func _ready() -> void:
|
|||||||
add_child(shape)
|
add_child(shape)
|
||||||
for index in 10:
|
for index in 10:
|
||||||
_points.append(Vector2.RIGHT.rotated(TAU * index / 10) * _rng.randf_range(23, 35))
|
_points.append(Vector2.RIGHT.rotated(TAU * index / 10) * _rng.randf_range(23, 35))
|
||||||
|
_asteroid_sprite = Sprite2D.new()
|
||||||
|
_asteroid_sprite.name = "AsteroidSprite"
|
||||||
|
_asteroid_sprite.texture = ASTEROID_TEXTURES[posmod(reward_seed, ASTEROID_TEXTURES.size())]
|
||||||
|
var texture_size := _asteroid_sprite.texture.get_size()
|
||||||
|
_asteroid_sprite.scale = Vector2.ONE * (78.0 / maxf(texture_size.x, texture_size.y))
|
||||||
|
_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)
|
||||||
|
add_child(_asteroid_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)
|
||||||
@ -48,17 +59,15 @@ func _ready() -> void:
|
|||||||
_update_label(false)
|
_update_label(false)
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if is_instance_valid(_asteroid_sprite) and not _claimed:
|
||||||
|
_asteroid_sprite.rotation += _asteroid_spin * delta
|
||||||
|
|
||||||
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:
|
func _draw() -> void:
|
||||||
if kind == "asteroid":
|
if kind == "wreck":
|
||||||
draw_colored_polygon(_points, Color("655e56"))
|
|
||||||
var outline := _points.duplicate()
|
|
||||||
outline.append(_points[0])
|
|
||||||
draw_polyline(outline, Color("a39a88"), 2, true)
|
|
||||||
draw_circle(Vector2(-8, -5), 7, Color("49443f"))
|
|
||||||
elif kind == "wreck":
|
|
||||||
draw_colored_polygon(PackedVector2Array([Vector2(-38, 20), Vector2(-16, -30), Vector2(7, -12), Vector2(22, 27), Vector2(-5, 14)]), Color("626b78"))
|
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_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"))
|
draw_colored_polygon(PackedVector2Array([Vector2(28, -16), Vector2(42, -5), Vector2(29, 8)]), Color("434e60"))
|
||||||
|
|||||||
@ -8,14 +8,16 @@ const BALANCE := preload("res://scripts/captain/captain_balance.gd")
|
|||||||
@onready var xp_bar: ProgressBar = $Contents/XPBar
|
@onready var xp_bar: ProgressBar = $Contents/XPBar
|
||||||
@onready var credits_label: Label = $Contents/Wallet/Credits
|
@onready var credits_label: Label = $Contents/Wallet/Credits
|
||||||
@onready var points_label: Label = $Contents/Wallet/Points
|
@onready var points_label: Label = $Contents/Wallet/Points
|
||||||
@onready var critical_label: Label = $Contents/Critical
|
|
||||||
|
|
||||||
|
var _collapsed := false
|
||||||
|
var _collapse_button: Button
|
||||||
var _captain: CaptainProgress
|
var _captain: CaptainProgress
|
||||||
var _rank_labels: Dictionary = {}
|
var _rank_labels: Dictionary = {}
|
||||||
var _effect_labels: Dictionary = {}
|
var _effect_labels: Dictionary = {}
|
||||||
var _buttons: Dictionary = {}
|
var _buttons: Dictionary = {}
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_build_portrait()
|
||||||
_captain = GameState.captain
|
_captain = GameState.captain
|
||||||
_captain.normalize_skill_ranks()
|
_captain.normalize_skill_ranks()
|
||||||
for skill in BALANCE.SKILL_NAMES:
|
for skill in BALANCE.SKILL_NAMES:
|
||||||
@ -53,6 +55,8 @@ 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)):
|
||||||
|
_toggle_collapsed()
|
||||||
|
|
||||||
func _train(skill: String) -> void:
|
func _train(skill: String) -> void:
|
||||||
_captain.train_skill(skill)
|
_captain.train_skill(skill)
|
||||||
@ -73,4 +77,63 @@ func _refresh() -> void:
|
|||||||
var next_bonus := BALANCE.skill_bonus(skill, rank + 1)
|
var next_bonus := BALANCE.skill_bonus(skill, rank + 1)
|
||||||
_buttons[skill].tooltip_text = BALANCE.SKILL_HELP[skill] + ("\nOsiągnięto limit 20 punktów." if rank >= BALANCE.MAX_SKILL_RANK else "\nNastępny punkt: %.1f%% → %.1f%%" % [bonus * 100.0, next_bonus * 100.0])
|
_buttons[skill].tooltip_text = BALANCE.SKILL_HELP[skill] + ("\nOsiągnięto limit 20 punktów." if rank >= BALANCE.MAX_SKILL_RANK else "\nNastępny punkt: %.1f%% → %.1f%%" % [bonus * 100.0, next_bonus * 100.0])
|
||||||
_buttons[skill].disabled = not _captain.can_train(skill)
|
_buttons[skill].disabled = not _captain.can_train(skill)
|
||||||
critical_label.text = "Krytyk: %.1f%% · ×%.2f\nCzęści: %.1f" % [float(player.call("get_critical_chance")) * 100.0, float(player.call("get_critical_multiplier")), _captain.parts]
|
|
||||||
|
func _build_portrait() -> void:
|
||||||
|
custom_minimum_size = Vector2(320, 0)
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
style.bg_color = Color(0.025, 0.042, 0.064, 0.96)
|
||||||
|
style.border_color = Color("376779")
|
||||||
|
style.set_border_width_all(1)
|
||||||
|
style.set_corner_radius_all(8)
|
||||||
|
style.set_content_margin_all(10)
|
||||||
|
add_theme_stylebox_override("panel", style)
|
||||||
|
_collapse_button = Button.new()
|
||||||
|
_collapse_button.name = "CollapseCaptain"
|
||||||
|
_collapse_button.text = "−"
|
||||||
|
_collapse_button.flat = true
|
||||||
|
_collapse_button.focus_mode = Control.FOCUS_NONE
|
||||||
|
_collapse_button.custom_minimum_size = Vector2(24, 24)
|
||||||
|
_collapse_button.pressed.connect(_toggle_collapsed)
|
||||||
|
$Contents/Header.add_child(_collapse_button)
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.name = "PortraitRow"
|
||||||
|
row.add_theme_constant_override("separation", 10)
|
||||||
|
$Contents.add_child(row)
|
||||||
|
$Contents.move_child(row, 1)
|
||||||
|
var frame := PanelContainer.new()
|
||||||
|
frame.name = "AvatarFrame"
|
||||||
|
var portrait_style := style.duplicate() as StyleBoxFlat
|
||||||
|
portrait_style.set_content_margin_all(2)
|
||||||
|
portrait_style.border_color = Color("daa85d")
|
||||||
|
frame.add_theme_stylebox_override("panel", portrait_style)
|
||||||
|
row.add_child(frame)
|
||||||
|
var portrait := TextureRect.new()
|
||||||
|
portrait.name = "CaptainAvatar"
|
||||||
|
portrait.custom_minimum_size = Vector2(76, 76)
|
||||||
|
portrait.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
portrait.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
|
||||||
|
portrait.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
if ResourceLoader.exists("res://assets/avatars/captain.png"):
|
||||||
|
portrait.texture = load("res://assets/avatars/captain.png")
|
||||||
|
frame.add_child(portrait)
|
||||||
|
var info := VBoxContainer.new()
|
||||||
|
info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
info.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
|
row.add_child(info)
|
||||||
|
var designation := Label.new()
|
||||||
|
designation.text = "DOWÓDCA STATKU"
|
||||||
|
designation.add_theme_font_size_override("font_size", 11)
|
||||||
|
designation.add_theme_color_override("font_color", Color("91dbea"))
|
||||||
|
info.add_child(designation)
|
||||||
|
xp_label.reparent(info, false)
|
||||||
|
xp_bar.reparent(info, false)
|
||||||
|
xp_bar.custom_minimum_size.y = 5
|
||||||
|
|
||||||
|
func _toggle_collapsed() -> void:
|
||||||
|
_collapsed = not _collapsed
|
||||||
|
GameState.hud_panel_state["captain_collapsed"] = _collapsed
|
||||||
|
for child in $Contents.get_children():
|
||||||
|
if child.name not in ["Header", "PortraitRow"]:
|
||||||
|
child.visible = not _collapsed
|
||||||
|
_collapse_button.text = "+" if _collapsed else "−"
|
||||||
|
size.y = get_combined_minimum_size().y
|
||||||
|
|||||||
@ -7,6 +7,7 @@ extends PanelContainer
|
|||||||
@onready var slot_label: Label = $SlotLabel
|
@onready var slot_label: Label = $SlotLabel
|
||||||
|
|
||||||
var _inventory: ShipInventory
|
var _inventory: ShipInventory
|
||||||
|
var _icon: TextureRect
|
||||||
var _delete_button: Button
|
var _delete_button: Button
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -16,6 +17,7 @@ func _ready() -> void:
|
|||||||
add_child(overlay)
|
add_child(overlay)
|
||||||
_delete_button = Button.new()
|
_delete_button = Button.new()
|
||||||
_delete_button.text = "x"
|
_delete_button.text = "x"
|
||||||
|
_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.flat = true
|
||||||
_delete_button.add_theme_font_size_override("font_size", 13)
|
_delete_button.add_theme_font_size_override("font_size", 13)
|
||||||
@ -33,27 +35,19 @@ func _ready() -> void:
|
|||||||
if _inventory:
|
if _inventory:
|
||||||
_inventory.inventory_changed.connect(_refresh)
|
_inventory.inventory_changed.connect(_refresh)
|
||||||
_inventory.ammunition_changed.connect(_refresh)
|
_inventory.ammunition_changed.connect(_refresh)
|
||||||
match slot_kind:
|
custom_minimum_size = Vector2(72, 72) if slot_kind == "cargo" else Vector2(64, 64)
|
||||||
"weapon":
|
slot_label.custom_minimum_size = Vector2.ZERO
|
||||||
custom_minimum_size = Vector2(90, 38)
|
slot_label.add_theme_font_size_override("font_size", 9)
|
||||||
"module":
|
_icon = TextureRect.new()
|
||||||
custom_minimum_size = Vector2(104, 36)
|
_icon.name = "ItemIcon"
|
||||||
_:
|
_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
custom_minimum_size = Vector2(148, 56)
|
_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
slot_label.add_theme_font_size_override("font_size", 10)
|
_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
slot_label.custom_minimum_size.y = 36
|
add_child(_icon)
|
||||||
slot_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
||||||
slot_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
||||||
slot_label.text_overrun_behavior = TextServer.OVERRUN_NO_TRIMMING
|
|
||||||
if overlay_slot:
|
if overlay_slot:
|
||||||
custom_minimum_size.y = 44
|
|
||||||
slot_label.custom_minimum_size.y = 32
|
|
||||||
slot_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
||||||
slot_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
||||||
slot_label.text_overrun_behavior = TextServer.OVERRUN_NO_TRIMMING
|
|
||||||
var binding := Label.new()
|
var binding := Label.new()
|
||||||
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
binding.text = (["LPM", "PPM", "ŚPM"][slot_index]) if slot_kind == "weapon" else str(slot_index + 1)
|
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, -14)
|
||||||
binding.add_theme_font_size_override("font_size", 9)
|
binding.add_theme_font_size_override("font_size", 9)
|
||||||
binding.add_theme_color_override("font_color", Color("a0b2c4"))
|
binding.add_theme_color_override("font_color", Color("a0b2c4"))
|
||||||
@ -65,11 +59,11 @@ func _ready() -> void:
|
|||||||
_refresh()
|
_refresh()
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT:
|
if slot_kind == "weapon" and _has_missile():
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
func _draw() -> void:
|
func _draw() -> void:
|
||||||
if slot_kind != "weapon" or slot_index != ShipInventory.MISSILE_SLOT or _inventory == null:
|
if slot_kind != "weapon" or not _has_missile() or _inventory == null:
|
||||||
return
|
return
|
||||||
var weapons := _inventory.ship.get_node("WeaponController")
|
var weapons := _inventory.ship.get_node("WeaponController")
|
||||||
var remaining := float(weapons.get("missile_cooldown_remaining"))
|
var remaining := float(weapons.get("missile_cooldown_remaining"))
|
||||||
@ -83,14 +77,17 @@ func _refresh() -> void:
|
|||||||
return
|
return
|
||||||
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
||||||
_apply_slot_style(item)
|
_apply_slot_style(item)
|
||||||
tooltip_text = item.get_tooltip_text() if item != null else ("WYRZUTNIA [ŚPM] — przeciągnij wyrzutnię z magazynu." if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT else "")
|
_icon.texture = item.definition.icon if item != null and item.definition != null else _empty_icon()
|
||||||
if item != null and slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT:
|
_icon.modulate = Color(1, 1, 1, 1.0 if item != null else 0.16)
|
||||||
|
slot_label.visible = _icon.texture == null
|
||||||
|
tooltip_text = item.get_tooltip_text() if item != null else _empty_slot_text()
|
||||||
|
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:
|
if _delete_button:
|
||||||
_delete_button.visible = item != null
|
_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 = "RAKIETY" if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT else ""
|
slot_label.text = "—"
|
||||||
return
|
return
|
||||||
var definition := item.definition
|
var definition := item.definition
|
||||||
slot_label.add_theme_color_override("font_color", Color("f1f4f8"))
|
slot_label.add_theme_color_override("font_color", Color("f1f4f8"))
|
||||||
@ -102,8 +99,9 @@ func _apply_slot_style(item: ItemInstance) -> void:
|
|||||||
style.border_color = Color("354455")
|
style.border_color = Color("354455")
|
||||||
style.set_border_width_all(1)
|
style.set_border_width_all(1)
|
||||||
style.set_content_margin_all(5)
|
style.set_content_margin_all(5)
|
||||||
|
style.set_corner_radius_all(4)
|
||||||
if slot_kind == "cargo":
|
if slot_kind == "cargo":
|
||||||
style.content_margin_right = 18
|
style.content_margin_right = 5
|
||||||
if item != null and item.definition != null:
|
if item != null and item.definition != null:
|
||||||
style.border_color = item.get_type_color()
|
style.border_color = item.get_type_color()
|
||||||
style.bg_color = item.get_background_color()
|
style.bg_color = item.get_background_color()
|
||||||
@ -148,19 +146,61 @@ func _make_custom_tooltip(for_text: String) -> Object:
|
|||||||
label.add_text(("★ " if quality == 2 else "") + line + "\n")
|
label.add_text(("★ " if quality == 2 else "") + line + "\n")
|
||||||
if quality > 0:
|
if quality > 0:
|
||||||
label.pop()
|
label.pop()
|
||||||
panel.add_child(label)
|
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)
|
||||||
return panel
|
return panel
|
||||||
|
|
||||||
|
func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||||
|
var module_index := ShipInventory.MODULE_CATEGORIES.find(item.definition.category)
|
||||||
|
if module_index < 0:
|
||||||
|
return
|
||||||
|
columns.add_child(VSeparator.new())
|
||||||
|
var comparison := RichTextLabel.new()
|
||||||
|
comparison.name = "EquipmentComparison"
|
||||||
|
comparison.fit_content = true
|
||||||
|
comparison.scroll_active = false
|
||||||
|
comparison.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
comparison.custom_minimum_size.x = 290
|
||||||
|
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"))
|
||||||
|
columns.add_child(comparison)
|
||||||
|
var equipped := _inventory.get_item("module", module_index)
|
||||||
|
comparison.add_text("ZMIANY PO ZAŁOŻENIU\n")
|
||||||
|
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")
|
||||||
|
var rows := _inventory.get_item_comparison(item, equipped)
|
||||||
|
if rows.is_empty():
|
||||||
|
comparison.add_text("Bez zmian w bonusach.\n")
|
||||||
|
for row in rows:
|
||||||
|
comparison.push_color(Color("79e6a0") if row["delta"] > 0.0 else Color("ff8989"))
|
||||||
|
var name: String = row["name"]
|
||||||
|
comparison.add_text("%s: %+.2f %s\n" % [name, row["delta"], row["unit"]])
|
||||||
|
comparison.pop()
|
||||||
|
comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.")
|
||||||
|
|
||||||
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
|
||||||
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
||||||
if item == null:
|
if item == null:
|
||||||
return null
|
return null
|
||||||
var preview := Label.new()
|
if item.definition.icon != null:
|
||||||
preview.text = item.definition.display_name
|
var preview := TextureRect.new()
|
||||||
preview.add_theme_color_override("font_color", Color(0.85, 0.94, 1.0))
|
preview.texture = item.definition.icon
|
||||||
set_drag_preview(preview)
|
preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
preview.custom_minimum_size = Vector2(64, 64)
|
||||||
|
set_drag_preview(preview)
|
||||||
|
else:
|
||||||
|
var preview := Label.new()
|
||||||
|
preview.text = item.definition.display_name
|
||||||
|
set_drag_preview(preview)
|
||||||
return {"from_kind": slot_kind, "from_index": slot_index}
|
return {"from_kind": slot_kind, "from_index": slot_index}
|
||||||
|
|
||||||
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
|
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
|
||||||
@ -183,12 +223,19 @@ func _drop_data(_at_position: Vector2, data: Variant) -> void:
|
|||||||
slot_index
|
slot_index
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func _has_missile() -> bool:
|
||||||
|
if _inventory == null or slot_kind != "weapon":
|
||||||
|
return false
|
||||||
|
var item := _inventory.get_item(slot_kind, slot_index)
|
||||||
|
return item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE
|
||||||
|
|
||||||
func _empty_slot_text() -> String:
|
func _empty_slot_text() -> String:
|
||||||
if slot_kind == "weapon":
|
if slot_kind == "weapon":
|
||||||
var weapon_binding := "LPM" if slot_index == 0 else "PPM"
|
return "BROŃ [%s]" % ["LPM", "PPM", "ŚPM"][slot_index]
|
||||||
return "BROŃ %d [%s]\nPUSTY" % [slot_index + 1, weapon_binding]
|
|
||||||
if slot_kind == "module":
|
if slot_kind == "module":
|
||||||
return "MODUŁ %d [%d]\nPUSTY" % [slot_index + 1, slot_index + 1]
|
return ShipInventory.MODULE_NAMES[slot_index].to_upper()
|
||||||
|
if slot_kind == "extension":
|
||||||
|
return "ROZSZ. [%d]" % (slot_index + 1)
|
||||||
return "PUSTY"
|
return "PUSTY"
|
||||||
|
|
||||||
func _category_name(category: int) -> String:
|
func _category_name(category: int) -> String:
|
||||||
@ -197,12 +244,14 @@ func _category_name(category: int) -> String:
|
|||||||
return "BROŃ"
|
return "BROŃ"
|
||||||
ItemDefinition.Category.SHIELD:
|
ItemDefinition.Category.SHIELD:
|
||||||
return "TARCZA"
|
return "TARCZA"
|
||||||
ItemDefinition.Category.HULL:
|
ItemDefinition.Category.ARMOR:
|
||||||
return "KADŁUB"
|
return "PANCERZ"
|
||||||
ItemDefinition.Category.GENERATOR:
|
ItemDefinition.Category.REACTOR:
|
||||||
return "GENERATOR"
|
return "REAKTOR"
|
||||||
ItemDefinition.Category.EXTENSION:
|
ItemDefinition.Category.ENGINE:
|
||||||
return "MODUŁ PASYWNY"
|
return "SILNIK"
|
||||||
|
ItemDefinition.Category.COMPUTER:
|
||||||
|
return "KOMPUTER"
|
||||||
ItemDefinition.Category.ACTIVE_EXTENSION:
|
ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
return "ROZSZERZENIE"
|
return "ROZSZERZENIE"
|
||||||
return "PRZEDMIOT"
|
return "PRZEDMIOT"
|
||||||
@ -216,3 +265,9 @@ func _stat_text(item: ItemInstance) -> String:
|
|||||||
var total_value := item.get_stat_total(definition.primary_stat)
|
var total_value := item.get_stat_total(definition.primary_stat)
|
||||||
var sign_text := "+" if total_value >= 0.0 else ""
|
var sign_text := "+" if total_value >= 0.0 else ""
|
||||||
return "%s%.0f%s · Poz. %d" % [sign_text, total_value, definition.stat_suffix, item.item_level]
|
return "%s%.0f%s · Poz. %d" % [sign_text, total_value, definition.stat_suffix, item.item_level]
|
||||||
|
|
||||||
|
func _empty_icon() -> Texture2D:
|
||||||
|
if slot_kind != "module":
|
||||||
|
return null
|
||||||
|
var names := ["shield", "armor", "engine", "reactor", "computer"]
|
||||||
|
return load("res://assets/icons/%s.png" % names[slot_index]) as Texture2D
|
||||||
|
|||||||
68
scripts/ui/flight_cockpit.gd
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
const FONT := preload("res://assets/fonts/font2.ttf")
|
||||||
|
const CYAN := Color("91dbea")
|
||||||
|
const WEAPON_DISPLAY_ORDER := [0, 2, 1]
|
||||||
|
const AMBER := Color("efb568")
|
||||||
|
var player: CharacterBody2D
|
||||||
|
var game: Node2D
|
||||||
|
var _inventory: ShipInventory
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
_inventory = player.get_node("ShipInventory")
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if is_instance_valid(player):
|
||||||
|
var screen := get_viewport().get_canvas_transform() * player.global_position
|
||||||
|
var local := get_global_transform().affine_inverse() * screen
|
||||||
|
var overlaps := Rect2(Vector2.ZERO, size).grow(36).has_point(local)
|
||||||
|
modulate.a = move_toward(modulate.a, 0.18 if overlaps else 1.0, delta * 4.0)
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _text(value: String, point: Vector2, width: float, font_size: int, color: Color) -> void:
|
||||||
|
draw_string(FONT, point, value, HORIZONTAL_ALIGNMENT_CENTER, width, font_size, color)
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if _inventory == null or not is_instance_valid(player) or size.x < 50 or size.y < 50:
|
||||||
|
return
|
||||||
|
var outline := PackedVector2Array([Vector2(24, 0), Vector2(size.x - 24, 0), Vector2(size.x, 24), Vector2(size.x, size.y - 12), Vector2(size.x - 12, size.y), Vector2(12, size.y), Vector2(0, size.y - 12), Vector2(0, 24)])
|
||||||
|
draw_colored_polygon(outline, Color(0.025, 0.041, 0.063, 0.96))
|
||||||
|
var closed := outline.duplicate()
|
||||||
|
closed.append(outline[0])
|
||||||
|
draw_polyline(closed, Color("376779"), 1.5, true)
|
||||||
|
draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true)
|
||||||
|
var cell := (size.x - 40) / 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 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 < 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 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)
|
||||||
|
if item != null and item.definition.icon != null:
|
||||||
|
draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(11, 18), Vector2(42, 42)), 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])
|
||||||
|
|
||||||
|
func _card_style(color: Color) -> StyleBoxFlat:
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
style.bg_color = Color("0b1520")
|
||||||
|
style.border_color = color
|
||||||
|
style.set_border_width_all(1)
|
||||||
|
style.set_corner_radius_all(4)
|
||||||
|
return style
|
||||||
1
scripts/ui/flight_cockpit.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://srdh8udwbrvj
|
||||||
@ -67,12 +67,12 @@ func _position_at_planet() -> void:
|
|||||||
var planet_radius := float(planet.get("radius")) * canvas.x.length()
|
var planet_radius := float(planet.get("radius")) * canvas.x.length()
|
||||||
size = panel.get_combined_minimum_size()
|
size = panel.get_combined_minimum_size()
|
||||||
var viewport_size := get_viewport_rect().size
|
var viewport_size := get_viewport_rect().size
|
||||||
var sidebar := get_parent().get_node_or_null("CaptainShipDrawer") as Control
|
var sidebar := get_parent().get_node_or_null("ShipDrawer") as Control
|
||||||
var screen_right := viewport_size.x - (sidebar.size.x + 8.0 if sidebar != null and sidebar.visible else 8.0)
|
var screen_right := viewport_size.x - (sidebar.size.x + 8.0 if sidebar != null and sidebar.visible else 8.0)
|
||||||
var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5)
|
var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5)
|
||||||
if target.x + size.x > screen_right:
|
if target.x + size.x > screen_right:
|
||||||
target.x = planet_screen.x - planet_radius - 24.0 - size.x
|
target.x = planet_screen.x - planet_radius - 24.0 - size.x
|
||||||
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 80.0)))
|
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 150.0)))
|
||||||
|
|
||||||
func _refresh_ammunition_service() -> void:
|
func _refresh_ammunition_service() -> void:
|
||||||
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
||||||
|
|||||||
@ -2,27 +2,34 @@ extends Control
|
|||||||
|
|
||||||
const FONT := preload("res://assets/fonts/font2.ttf")
|
const FONT := preload("res://assets/fonts/font2.ttf")
|
||||||
var player: CharacterBody2D
|
var player: CharacterBody2D
|
||||||
var remaining := 8.0
|
|
||||||
var targets: Array[Node2D] = []
|
var targets: Array[Node2D] = []
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
for group in ["enemies", "exploration_pois"]:
|
|
||||||
for target in get_tree().get_nodes_in_group(group):
|
|
||||||
if player.get_parent().is_ancestor_of(target):
|
|
||||||
targets.append(target)
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
remaining -= delta
|
|
||||||
if remaining <= 0 or not is_instance_valid(player) or bool(player.get("_is_destroyed")):
|
|
||||||
get_parent().queue_free()
|
|
||||||
return
|
|
||||||
queue_redraw()
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
if not is_instance_valid(player):
|
if not is_instance_valid(player):
|
||||||
return
|
return
|
||||||
var bounds := Rect2(Vector2(45, 100), Vector2(maxf(100, size.x - 390), maxf(100, size.y - 210)))
|
targets.clear()
|
||||||
|
for group in ["enemies", "exploration_pois"]:
|
||||||
|
for target in get_tree().get_nodes_in_group(group):
|
||||||
|
if player.get_parent().is_ancestor_of(target) and is_target_in_range(target):
|
||||||
|
targets.append(target)
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func get_scan_range() -> float:
|
||||||
|
var transform := get_viewport().get_canvas_transform()
|
||||||
|
var half_screen := get_viewport_rect().size * 0.5
|
||||||
|
var visible_radius := Vector2(half_screen.x / transform.x.length(), half_screen.y / transform.y.length()).length()
|
||||||
|
return maxf(float(player.get("base_scanner_range")), visible_radius + 150.0) + float(player.get("scanner_range")) - float(player.get("base_scanner_range"))
|
||||||
|
|
||||||
|
func is_target_in_range(target: Node2D) -> bool:
|
||||||
|
return player.global_position.distance_to(target.global_position) <= get_scan_range()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if not is_instance_valid(player) or bool(player.get("_is_destroyed")) or bool(player.get("is_docked")):
|
||||||
|
return
|
||||||
|
var bounds := Rect2(Vector2(344, 70), Vector2(maxf(100, size.x - 680), maxf(100, size.y - 230)))
|
||||||
var origin := get_viewport().get_canvas_transform() * player.global_position
|
var origin := get_viewport().get_canvas_transform() * player.global_position
|
||||||
var anchor := Vector2(clampf(origin.x, bounds.position.x, bounds.end.x), clampf(origin.y, bounds.position.y, bounds.end.y))
|
var anchor := Vector2(clampf(origin.x, bounds.position.x, bounds.end.x), clampf(origin.y, bounds.position.y, bounds.end.y))
|
||||||
for target in targets:
|
for target in targets:
|
||||||
@ -45,6 +52,8 @@ func _draw() -> void:
|
|||||||
color = Color("d2a4ff")
|
color = Color("d2a4ff")
|
||||||
caption = "?"
|
caption = "?"
|
||||||
var screen := get_viewport().get_canvas_transform() * target.global_position
|
var screen := get_viewport().get_canvas_transform() * target.global_position
|
||||||
|
if get_viewport_rect().has_point(screen):
|
||||||
|
continue
|
||||||
var direction := (screen - anchor).normalized()
|
var direction := (screen - anchor).normalized()
|
||||||
var point := screen
|
var point := screen
|
||||||
if not bounds.has_point(screen):
|
if not bounds.has_point(screen):
|
||||||
@ -55,4 +64,3 @@ func _draw() -> void:
|
|||||||
var side := Vector2(-direction.y, direction.x)
|
var side := Vector2(-direction.y, direction.x)
|
||||||
draw_colored_polygon(PackedVector2Array([point + direction * 10, point - direction * 6 + side * 6, point - direction * 6 - side * 6]), color)
|
draw_colored_polygon(PackedVector2Array([point + direction * 10, point - direction * 6 + side * 6, point - direction * 6 - side * 6]), color)
|
||||||
draw_string(FONT, point + Vector2(-18, 25), caption, HORIZONTAL_ALIGNMENT_LEFT, -1, 11, color)
|
draw_string(FONT, point + Vector2(-18, 25), caption, HORIZONTAL_ALIGNMENT_LEFT, -1, 11, color)
|
||||||
draw_string(FONT, Vector2(32, 82), "SKANER %.1f s · czerwony: wrogowie · błękitny: asteroidy · złoty: wraki · fioletowy: antyczne planety" % maxf(0, remaining), HORIZONTAL_ALIGNMENT_LEFT, -1, 13, Color("c9e8ff"))
|
|
||||||
|
|||||||
73
scripts/ui/ship_crafting_panel.gd
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
extends PanelContainer
|
||||||
|
|
||||||
|
var _inventory: ShipInventory
|
||||||
|
var _expanded := false
|
||||||
|
var _toggle: Button
|
||||||
|
var _details: VBoxContainer
|
||||||
|
var _parts: Label
|
||||||
|
var _stock: Label
|
||||||
|
var _ammo: Button
|
||||||
|
var _missile: Button
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
||||||
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
|
var contents := VBoxContainer.new()
|
||||||
|
contents.name = "Contents"
|
||||||
|
contents.add_theme_constant_override("separation", 6)
|
||||||
|
add_child(contents)
|
||||||
|
_toggle = Button.new()
|
||||||
|
_toggle.name = "CreateToggle"
|
||||||
|
_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
|
||||||
|
_toggle.pressed.connect(_toggle_expanded)
|
||||||
|
contents.add_child(_toggle)
|
||||||
|
_details = VBoxContainer.new()
|
||||||
|
_details.name = "CraftingDetails"
|
||||||
|
_details.add_theme_constant_override("separation", 6)
|
||||||
|
contents.add_child(_details)
|
||||||
|
_parts = _label(Color("efb568"))
|
||||||
|
_stock = _label(Color("91dbea"))
|
||||||
|
_ammo = _button("CraftAmmunition", "+%d AMUNICJI · %.0f CZĘŚCI" % [ShipInventory.AMMUNITION_CRAFT_AMOUNT, ShipInventory.AMMUNITION_CRAFT_PARTS_COST])
|
||||||
|
_ammo.tooltip_text = "Tworzy amunicję do działka maszynowego."
|
||||||
|
_ammo.pressed.connect(func() -> void: _inventory.craft_ammunition())
|
||||||
|
_missile = _button("CraftMissile", "+1 RAKIETA · %.0f CZĘŚCI" % ShipInventory.MISSILE_CRAFT_PARTS_COST)
|
||||||
|
_missile.tooltip_text = "Tworzy rakietę do dowolnej wyrzutni."
|
||||||
|
_missile.pressed.connect(func() -> void: _inventory.craft_missile())
|
||||||
|
_details.hide()
|
||||||
|
if bool(GameState.hud_panel_state.get("crafting_expanded", false)):
|
||||||
|
_toggle_expanded()
|
||||||
|
_inventory.ammunition_changed.connect(_refresh)
|
||||||
|
GameState.captain.changed.connect(_refresh)
|
||||||
|
_refresh()
|
||||||
|
|
||||||
|
func _label(color: Color) -> Label:
|
||||||
|
var label := Label.new()
|
||||||
|
label.add_theme_font_size_override("font_size", 10)
|
||||||
|
label.add_theme_color_override("font_color", color)
|
||||||
|
_details.add_child(label)
|
||||||
|
return label
|
||||||
|
|
||||||
|
func _button(node_name: String, caption: String) -> Button:
|
||||||
|
var button := Button.new()
|
||||||
|
button.name = node_name
|
||||||
|
button.text = caption
|
||||||
|
button.custom_minimum_size.y = 32
|
||||||
|
button.add_theme_font_size_override("font_size", 10)
|
||||||
|
button.focus_mode = Control.FOCUS_NONE
|
||||||
|
_details.add_child(button)
|
||||||
|
return button
|
||||||
|
|
||||||
|
func _toggle_expanded() -> void:
|
||||||
|
_expanded = not _expanded
|
||||||
|
GameState.hud_panel_state["crafting_expanded"] = _expanded
|
||||||
|
_details.visible = _expanded
|
||||||
|
_toggle.text = "TWÓRZ ▴" if _expanded else "TWÓRZ ▾"
|
||||||
|
|
||||||
|
func _refresh() -> void:
|
||||||
|
_parts.text = "DOSTĘPNE CZĘŚCI: %.1f" % GameState.captain.parts
|
||||||
|
_stock.text = "AMUNICJA: %d / RAKIETY: %d" % [_inventory.ammunition, _inventory.missile_ammunition]
|
||||||
|
_ammo.disabled = not _inventory.can_craft_ammunition()
|
||||||
|
_missile.disabled = not _inventory.can_craft_missile()
|
||||||
1
scripts/ui/ship_crafting_panel.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://njdq3ttvccwm
|
||||||
@ -7,31 +7,17 @@ const CARGO_SIZE := 20
|
|||||||
@onready var close_button: Button = $Contents/Header/CloseButton
|
@onready var close_button: Button = $Contents/Header/CloseButton
|
||||||
@onready var title_label: Label = $Contents/Header/Title
|
@onready var title_label: Label = $Contents/Header/Title
|
||||||
@onready var ammunition_label: Label = $Contents/Ammunition/Count
|
@onready var ammunition_label: Label = $Contents/Ammunition/Count
|
||||||
@onready var craft_button: Button = $Contents/Ammunition/CraftButton
|
|
||||||
|
|
||||||
var _inventory: ShipInventory
|
var _inventory: ShipInventory
|
||||||
var _drawer_open := false
|
var _drawer_open := false
|
||||||
var _slide_tween: Tween
|
var _slide_tween: Tween
|
||||||
var _missile_button: Button
|
|
||||||
var _minerals_label: Label
|
var _minerals_label: Label
|
||||||
var drawer_width := 780.0
|
var drawer_width := 560.0
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
close_button.pressed.connect(close_drawer)
|
close_button.pressed.connect(close_drawer)
|
||||||
craft_button.pressed.connect(_craft_ammunition)
|
|
||||||
craft_button.text = "TWÓRZ +%d AMUNICJI (%.0f części)" % [ShipInventory.AMMUNITION_CRAFT_AMOUNT, ShipInventory.AMMUNITION_CRAFT_PARTS_COST]
|
|
||||||
var missile_row := HBoxContainer.new()
|
|
||||||
$Contents.add_child(missile_row)
|
|
||||||
$Contents.move_child(missile_row, $Contents/CargoGrid.get_index())
|
|
||||||
_missile_button = Button.new()
|
|
||||||
_missile_button.text = "TWÓRZ +1 RAKIETĘ (%.0f części)" % ShipInventory.MISSILE_CRAFT_PARTS_COST
|
|
||||||
_missile_button.tooltip_text = "Amunicja do obu typów wyrzutni rakiet. Wyrzutnie zdobywasz jako loot."
|
|
||||||
_missile_button.add_theme_font_size_override("font_size", 11)
|
|
||||||
_missile_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
_missile_button.pressed.connect(func() -> void: _inventory.craft_missile())
|
|
||||||
missile_row.add_child(_missile_button)
|
|
||||||
_minerals_label = Label.new()
|
_minerals_label = Label.new()
|
||||||
_minerals_label.add_theme_font_size_override("font_size", 12)
|
_minerals_label.add_theme_font_size_override("font_size", 10)
|
||||||
$Contents.add_child(_minerals_label)
|
$Contents.add_child(_minerals_label)
|
||||||
$Contents.move_child(_minerals_label, $Contents/CargoGrid.get_index())
|
$Contents.move_child(_minerals_label, $Contents/CargoGrid.get_index())
|
||||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
@ -48,16 +34,10 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func _refresh_title() -> void:
|
func _refresh_title() -> void:
|
||||||
_minerals_label.text = "SUROWCE · Tytan: %d · Żelazo: %d · Aluminium: %d" % [GameState.captain.minerals.get("titanium", 0), GameState.captain.minerals.get("iron", 0), GameState.captain.minerals.get("aluminium", 0)]
|
_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)]
|
||||||
craft_button.disabled = _inventory == null or not _inventory.can_craft_ammunition()
|
|
||||||
_missile_button.disabled = _inventory == null or not _inventory.can_craft_missile()
|
|
||||||
if _inventory:
|
if _inventory:
|
||||||
title_label.text = "MAGAZYN (%d/%d) · Części: %.1f" % [_inventory.get_cargo_used(), CARGO_SIZE, GameState.captain.parts]
|
title_label.text = "MAGAZYN (%d/%d) · 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 = "AMUNICJA: %d · RAKIETY: %d" % [_inventory.ammunition, _inventory.get_missile_count()]
|
||||||
|
|
||||||
func _craft_ammunition() -> void:
|
|
||||||
if _inventory:
|
|
||||||
_inventory.craft_ammunition()
|
|
||||||
|
|
||||||
func toggle_drawer() -> void:
|
func toggle_drawer() -> void:
|
||||||
_set_drawer_open(not _drawer_open)
|
_set_drawer_open(not _drawer_open)
|
||||||
|
|
||||||
@ -66,6 +46,7 @@ func close_drawer(immediately: bool = false) -> void:
|
|||||||
if _slide_tween != null and _slide_tween.is_running():
|
if _slide_tween != null and _slide_tween.is_running():
|
||||||
_slide_tween.kill()
|
_slide_tween.kill()
|
||||||
_drawer_open = false
|
_drawer_open = false
|
||||||
|
GameState.hud_panel_state["inventory_open"] = false
|
||||||
position.x = drawer_width
|
position.x = drawer_width
|
||||||
hide()
|
hide()
|
||||||
return
|
return
|
||||||
@ -75,6 +56,7 @@ func _set_drawer_open(value: bool) -> void:
|
|||||||
if _slide_tween != null and _slide_tween.is_running():
|
if _slide_tween != null and _slide_tween.is_running():
|
||||||
_slide_tween.kill()
|
_slide_tween.kill()
|
||||||
_drawer_open = value
|
_drawer_open = value
|
||||||
|
GameState.hud_panel_state["inventory_open"] = value
|
||||||
if value and not visible:
|
if value and not visible:
|
||||||
position = Vector2(drawer_width, 0)
|
position = Vector2(drawer_width, 0)
|
||||||
show()
|
show()
|
||||||
|
|||||||
@ -7,9 +7,11 @@ func equip(inventory: ShipInventory, id: String, slot: int) -> void:
|
|||||||
for index in inventory.cargo.size():
|
for index in inventory.cargo.size():
|
||||||
var item := inventory.cargo[index]
|
var item := inventory.cargo[index]
|
||||||
if item != null and item.definition.item_id == id:
|
if item != null and item.definition.item_id == id:
|
||||||
assert(inventory.move_item("cargo", index, "module", slot))
|
assert(inventory.move_item("cargo", index, "extension", slot))
|
||||||
return
|
return
|
||||||
assert(false, "Starter extension missing: " + id)
|
var item := GENERATOR.generate_for_definition(load("res://resources/items/%s.tres" % id), 1)
|
||||||
|
assert(inventory.add_item(item))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(item), "extension", slot))
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
GameState.start_new_run()
|
GameState.start_new_run()
|
||||||
@ -21,7 +23,7 @@ func _ready() -> void:
|
|||||||
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||||
equip(inventory, "afterburner", 0)
|
equip(inventory, "afterburner", 0)
|
||||||
equip(inventory, "shield_charge", 1)
|
equip(inventory, "shield_charge", 1)
|
||||||
equip(inventory, "repair_drones", 5)
|
equip(inventory, "repair_drones", 4)
|
||||||
assert(ship.call("get_active_ability", 2) == null)
|
assert(ship.call("get_active_ability", 2) == null)
|
||||||
assert(not ship.call("activate_ability", 2))
|
assert(not ship.call("activate_ability", 2))
|
||||||
ship.set("energy", ship.get("max_energy") - 0.01)
|
ship.set("energy", ship.get("max_energy") - 0.01)
|
||||||
@ -38,19 +40,22 @@ func _ready() -> void:
|
|||||||
assert(ship.get("shields") == minf(100.0, ship.get("max_shields")))
|
assert(ship.get("shields") == minf(100.0, ship.get("max_shields")))
|
||||||
assert(not inventory.delete_cargo_item(-1))
|
assert(not inventory.delete_cargo_item(-1))
|
||||||
assert(GameState.captain.parts == 0.0)
|
assert(GameState.captain.parts == 0.0)
|
||||||
|
var salvage := ItemInstance.new()
|
||||||
|
salvage.definition = preload("res://resources/items/hull_plating.tres")
|
||||||
|
assert(inventory.add_item(salvage))
|
||||||
assert(inventory.delete_cargo_item(0))
|
assert(inventory.delete_cargo_item(0))
|
||||||
assert(not inventory.delete_cargo_item(0))
|
assert(not inventory.delete_cargo_item(0))
|
||||||
assert(GameState.captain.parts == 10.0)
|
assert(GameState.captain.parts == 10.0)
|
||||||
ship.set("hull", ship.get("max_hull") - 4.25)
|
ship.set("hull", ship.get("max_hull") - 4.25)
|
||||||
ship.set("energy", 0.0)
|
ship.set("energy", 0.0)
|
||||||
assert(ship.call("activate_ability", 5))
|
assert(ship.call("activate_ability", 4))
|
||||||
assert(ship.get("hull") == ship.get("max_hull"))
|
assert(ship.get("hull") == ship.get("max_hull"))
|
||||||
assert(is_equal_approx(GameState.captain.parts, 5.75) and ship.get("energy") == 0.0)
|
assert(is_equal_approx(GameState.captain.parts, 5.75) and ship.get("energy") == 0.0)
|
||||||
assert(not ship.call("activate_ability", 5))
|
assert(not ship.call("activate_ability", 4))
|
||||||
ship.set("hull", ship.get("max_hull") - 20.0)
|
ship.set("hull", ship.get("max_hull") - 20.0)
|
||||||
assert(ship.call("activate_ability", 5))
|
assert(ship.call("activate_ability", 4))
|
||||||
assert(GameState.captain.parts == 0.0)
|
assert(GameState.captain.parts == 0.0)
|
||||||
assert(not ship.call("activate_ability", 5))
|
assert(not ship.call("activate_ability", 4))
|
||||||
ship.set("energy", ship.get("max_energy"))
|
ship.set("energy", ship.get("max_energy"))
|
||||||
ship.velocity = Vector2.ZERO
|
ship.velocity = Vector2.ZERO
|
||||||
var key := InputEventKey.new()
|
var key := InputEventKey.new()
|
||||||
@ -74,15 +79,15 @@ func _ready() -> void:
|
|||||||
ship.set("energy", ship.get("max_energy"))
|
ship.set("energy", ship.get("max_energy"))
|
||||||
assert(not ship.call("activate_ability", 0))
|
assert(not ship.call("activate_ability", 0))
|
||||||
ship.set("is_docked", false)
|
ship.set("is_docked", false)
|
||||||
var item := inventory.get_item("module", 0)
|
var item := inventory.get_item("extension", 0)
|
||||||
assert(inventory.move_item("module", 0, "cargo", 0))
|
assert(inventory.move_item("extension", 0, "cargo", 0))
|
||||||
assert(ship.call("get_active_ability", 0) == null)
|
assert(ship.call("get_active_ability", 0) == null)
|
||||||
assert(inventory.move_item("cargo", 0, "module", 3))
|
assert(inventory.move_item("cargo", 0, "extension", 3))
|
||||||
assert(ship.call("get_active_ability", 3) == item.definition.active_ability)
|
assert(ship.call("get_active_ability", 3) == item.definition.active_ability)
|
||||||
for definition in GENERATOR.DEFINITIONS:
|
for definition in GENERATOR.DEFINITIONS:
|
||||||
if definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
if definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
var loot := GENERATOR.generate_for_definition(definition, 100)
|
var loot := GENERATOR.generate_for_definition(definition, 100)
|
||||||
assert(loot.definition.active_ability != null and not loot.additional_modifiers.is_empty())
|
assert(loot.definition.active_ability != null and loot.additional_modifiers.is_empty())
|
||||||
GameState.captain.parts = 17.5
|
GameState.captain.parts = 17.5
|
||||||
inventory.preserve_for_restart()
|
inventory.preserve_for_restart()
|
||||||
game.queue_free()
|
game.queue_free()
|
||||||
@ -91,6 +96,6 @@ func _ready() -> void:
|
|||||||
add_child(restarted)
|
add_child(restarted)
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
assert(GameState.captain.parts == 17.5)
|
assert(GameState.captain.parts == 17.5)
|
||||||
assert(restarted.get_node("PlayerShip/ShipInventory").get_item("module", 3) == item)
|
assert(restarted.get_node("PlayerShip/ShipInventory").get_item("extension", 3) == item)
|
||||||
assert(not restarted.get_node("PlayerShip").call("is_boosting"))
|
assert(not restarted.get_node("PlayerShip").call("is_boosting"))
|
||||||
print("ACTIVE_ABILITIES_TEST: PASS — costs, hotkeys, boost ramp/decay, salvage, repairs, equipment, loot, restart")
|
print("ACTIVE_ABILITIES_TEST: PASS — costs, hotkeys, boost ramp/decay, salvage, repairs, equipment, loot, restart")
|
||||||
|
|||||||
@ -16,10 +16,10 @@ func _ready() -> void:
|
|||||||
var launcher := ItemInstance.new()
|
var launcher := ItemInstance.new()
|
||||||
launcher.definition = ShipInventory.MISSILE_DEFINITIONS[0]
|
launcher.definition = ShipInventory.MISSILE_DEFINITIONS[0]
|
||||||
assert(inventory.add_item(launcher))
|
assert(inventory.add_item(launcher))
|
||||||
assert(not inventory.move_item("cargo", 0, "weapon", 0))
|
assert(inventory.can_move_item("cargo", 0, "weapon", 0))
|
||||||
assert(not inventory.move_item("weapon", 0, "weapon", 2))
|
assert(inventory.can_move_item("weapon", 0, "weapon", 2))
|
||||||
assert(inventory.move_item("cargo", 0, "weapon", 2))
|
assert(inventory.move_item("cargo", 0, "weapon", 2))
|
||||||
assert(not inventory.move_item("weapon", 2, "weapon", 0))
|
assert(inventory.can_move_item("weapon", 2, "weapon", 0))
|
||||||
assert(not inventory.move_item("weapon", 2, "module", 0))
|
assert(not inventory.move_item("weapon", 2, "module", 0))
|
||||||
var energy_before := float(ship.get("energy"))
|
var energy_before := float(ship.get("energy"))
|
||||||
var missile := inventory.weapon_slots[2]
|
var missile := inventory.weapon_slots[2]
|
||||||
@ -47,9 +47,9 @@ func _ready() -> void:
|
|||||||
weapons.set("missile_cooldown_remaining", 0.0)
|
weapons.set("missile_cooldown_remaining", 0.0)
|
||||||
assert(not weapons.call("try_fire_missile"))
|
assert(not weapons.call("try_fire_missile"))
|
||||||
assert(inventory.weapon_slots[2] == missile and ship.get("energy") == energy_before)
|
assert(inventory.weapon_slots[2] == missile and ship.get("energy") == energy_before)
|
||||||
GameState.captain.parts = 19.0
|
GameState.captain.parts = 49.0
|
||||||
assert(not inventory.craft_missile())
|
assert(not inventory.craft_missile())
|
||||||
GameState.captain.parts = 20.0
|
GameState.captain.parts = 50.0
|
||||||
assert(inventory.craft_missile() and GameState.captain.parts == 0.0)
|
assert(inventory.craft_missile() and GameState.captain.parts == 0.0)
|
||||||
var unguided := ItemInstance.new()
|
var unguided := ItemInstance.new()
|
||||||
unguided.definition = ShipInventory.MISSILE_DEFINITIONS[1]
|
unguided.definition = ShipInventory.MISSILE_DEFINITIONS[1]
|
||||||
@ -86,7 +86,7 @@ func _ready() -> void:
|
|||||||
if inventory.cargo[index] == null:
|
if inventory.cargo[index] == null:
|
||||||
inventory.cargo[index] = missile
|
inventory.cargo[index] = missile
|
||||||
var ammo_before := inventory.missile_ammunition
|
var ammo_before := inventory.missile_ammunition
|
||||||
assert(inventory.craft_missile() and GameState.captain.parts == 80.0)
|
assert(inventory.craft_missile() and GameState.captain.parts == 50.0)
|
||||||
assert(inventory.buy_missile() and GameState.captain.credits == 70)
|
assert(inventory.buy_missile() and GameState.captain.credits == 70)
|
||||||
assert(inventory.missile_ammunition == ammo_before + 2)
|
assert(inventory.missile_ammunition == ammo_before + 2)
|
||||||
addon.value = 100.0
|
addon.value = 100.0
|
||||||
|
|||||||
@ -3,44 +3,53 @@ const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
GameState.start_new_run()
|
GameState.start_new_run()
|
||||||
var ship := preload("res://scenes/game/player_ship.tscn").instantiate() as CharacterBody2D
|
var ship := preload("res://scenes/game/player_ship.tscn").instantiate() as CharacterBody2D
|
||||||
ship.name = "PlayerShip"
|
|
||||||
add_child(ship)
|
add_child(ship)
|
||||||
ship.set_physics_process(false)
|
ship.set_physics_process(false)
|
||||||
ship.get_node("WeaponController").set_physics_process(false)
|
var weapons := ship.get_node("WeaponController")
|
||||||
|
weapons.set_physics_process(false)
|
||||||
var inventory := ship.get_node("ShipInventory") as ShipInventory
|
var inventory := ship.get_node("ShipInventory") as ShipInventory
|
||||||
var scanner := GENERATOR.generate_for_definition(preload("res://resources/items/scanner.tres"), 5)
|
assert(inventory.module_slots.size() == 5 and inventory.extension_slots.size() == 5)
|
||||||
assert(scanner.get_addon_count() > 0)
|
var overlay := ship.get_node("ScannerOverlay").get_child(0)
|
||||||
assert(inventory.add_item(scanner))
|
var base_range: float = overlay.call("get_scan_range")
|
||||||
assert(inventory.move_item("cargo", inventory.cargo.find(scanner), "module", 0))
|
var energy_before: float = ship.get("energy")
|
||||||
var enemy := preload("res://scenes/game/enemy_ship.tscn").instantiate() as CharacterBody2D
|
var target := Node2D.new()
|
||||||
enemy.position = Vector2(900, 0)
|
target.position = Vector2(base_range + 100.0, 0)
|
||||||
add_child(enemy)
|
add_child(target)
|
||||||
enemy.set_physics_process(false)
|
target.add_to_group("exploration_pois")
|
||||||
for kind in ["asteroid", "wreck", "ruin"]:
|
assert(not overlay.call("is_target_in_range", target))
|
||||||
var poi := StaticBody2D.new()
|
var computer := GENERATOR.generate_for_definition(preload("res://resources/items/ship_computer.tres"), 5)
|
||||||
poi.set_script(preload("res://scripts/levels/exploration_poi.gd"))
|
assert(computer.get_addon_count() > 0)
|
||||||
poi.set("kind", kind)
|
assert(inventory.add_item(computer))
|
||||||
poi.set("player", ship)
|
for index in 4:
|
||||||
poi.position = Vector2(1500, 100)
|
assert(not inventory.can_move_item("cargo", inventory.cargo.find(computer), "module", index))
|
||||||
add_child(poi)
|
assert(not inventory.can_move_item("cargo", inventory.cargo.find(computer), "extension", 0))
|
||||||
poi.set_physics_process(false)
|
assert(inventory.move_item("cargo", inventory.cargo.find(computer), "module", 4))
|
||||||
var maximum := float(ship.get("max_energy"))
|
assert(overlay.call("is_target_in_range", target))
|
||||||
ship.set("energy", maximum * 0.49)
|
overlay.call("_process", 20.0)
|
||||||
assert(not ship.activate_ability(0))
|
assert(overlay.get("targets").has(target) and ship.get("energy") == energy_before)
|
||||||
ship.set("energy", maximum * 0.8)
|
for definition in GENERATOR.DEFINITIONS:
|
||||||
assert(ship.activate_ability(0))
|
if definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||||
assert(is_equal_approx(ship.get("energy"), maximum * 0.3))
|
var extension := GENERATOR.generate_for_definition(definition, 1000, 2)
|
||||||
var layer := ship.get_node("ScannerOverlay") as CanvasLayer
|
assert(extension.additional_modifiers.is_empty())
|
||||||
var overlay := layer.get_child(0) as Control
|
assert(inventory.add_item(extension))
|
||||||
assert(overlay.get("targets").size() == 4)
|
assert(not inventory.can_move_item("cargo", inventory.cargo.find(extension), "module", 0))
|
||||||
assert(overlay.mouse_filter == Control.MOUSE_FILTER_IGNORE)
|
assert(inventory.move_item("cargo", inventory.cargo.find(extension), "extension", 0))
|
||||||
assert(not ship.activate_ability(0))
|
var launcher := ItemInstance.new()
|
||||||
await get_tree().process_frame
|
launcher.definition = ShipInventory.MISSILE_DEFINITIONS[0]
|
||||||
overlay.call("_process", 8.1)
|
assert(inventory.add_item(launcher))
|
||||||
await get_tree().process_frame
|
for index in 3:
|
||||||
assert(not ship.has_node("ScannerOverlay"))
|
assert(inventory.move_item("cargo", inventory.cargo.find(launcher), "weapon", index))
|
||||||
ship.set("energy", maximum * 0.5)
|
weapons.set("missile_cooldown_remaining", 0.0)
|
||||||
assert(ship.activate_ability(0))
|
inventory.missile_ammunition = 1
|
||||||
assert(is_zero_approx(ship.get("energy")))
|
assert(weapons.call("try_fire_missile", index))
|
||||||
print("SCANNER_TEST: PASS loot addons, module activation, 50% max energy cost, four target types, repeat prevention, 8s expiry, reactivation")
|
assert(inventory.move_item("weapon", index, "cargo", inventory.cargo.find(null)))
|
||||||
|
assert(inventory.move_item("module", 4, "cargo", inventory.cargo.find(null)))
|
||||||
|
assert(is_equal_approx(overlay.call("get_scan_range"), base_range))
|
||||||
|
assert(not overlay.call("is_target_in_range", target))
|
||||||
|
inventory.preserve_for_restart()
|
||||||
|
var restored := preload("res://scenes/game/player_ship.tscn").instantiate()
|
||||||
|
add_child(restored)
|
||||||
|
restored.set_physics_process(false)
|
||||||
|
assert(restored.get_node("ShipInventory").extension_slots[0] == inventory.extension_slots[0])
|
||||||
|
print("SCANNER_TEST: PASS categories, extensions without addons, passive range, computer removal, all weapon slots, restart")
|
||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
|
|||||||
@ -54,7 +54,7 @@ func _ready() -> void:
|
|||||||
assert(profile.credits == 0)
|
assert(profile.credits == 0)
|
||||||
await _collect_credits(game.get_node("PlayerShip") as CharacterBody2D)
|
await _collect_credits(game.get_node("PlayerShip") as CharacterBody2D)
|
||||||
assert(profile.credits == 180)
|
assert(profile.credits == 180)
|
||||||
var panel := game.get_node("HUD/HUDRoot/CaptainShipDrawer/Scroll/Contents/CaptainPanel")
|
var panel := game.get_node("HUD/HUDRoot/CaptainPanel")
|
||||||
panel.get_node("Contents/Skills/gunner/Train_gunner").emit_signal("pressed")
|
panel.get_node("Contents/Skills/gunner/Train_gunner").emit_signal("pressed")
|
||||||
assert(profile.get_skill_rank("gunner") == 1 and profile.learning_points == 0)
|
assert(profile.get_skill_rank("gunner") == 1 and profile.learning_points == 0)
|
||||||
panel.get_node("Contents/Skills/piloting/Train_piloting").emit_signal("pressed")
|
panel.get_node("Contents/Skills/piloting/Train_piloting").emit_signal("pressed")
|
||||||
|
|||||||
98
tests/items/equipment_comparison_test.gd
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
extends Node
|
||||||
|
const GAME := preload("res://scenes/game/game.tscn")
|
||||||
|
|
||||||
|
func _modifier(key: String, value: float) -> ItemStatModifier:
|
||||||
|
var modifier := ItemStatModifier.new()
|
||||||
|
modifier.stat_key = key
|
||||||
|
modifier.value = value
|
||||||
|
return modifier
|
||||||
|
|
||||||
|
func _item(value: float) -> ItemInstance:
|
||||||
|
var item := ItemInstance.new()
|
||||||
|
item.definition = preload("res://resources/items/reinforced_shield.tres")
|
||||||
|
item.primary_value_override = value
|
||||||
|
return item
|
||||||
|
|
||||||
|
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 := _item(2.0)
|
||||||
|
old.additional_modifiers.append(_modifier("damage_percent", 10.0))
|
||||||
|
old.additional_modifiers.append(_modifier("shield_regeneration", 1.0))
|
||||||
|
var candidate := _item(3.0)
|
||||||
|
candidate.additional_modifiers.append(_modifier("damage_percent", 2.0))
|
||||||
|
candidate.additional_modifiers.append(_modifier("damage_percent", 3.0))
|
||||||
|
candidate.additional_modifiers.append(_modifier("energy_regeneration", 4.0))
|
||||||
|
assert(inventory.add_item(old))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(old), "module", 0))
|
||||||
|
assert(inventory.add_item(candidate))
|
||||||
|
var hull_before: float = ship.get("max_hull")
|
||||||
|
var shields_before: float = ship.get("max_shields")
|
||||||
|
var rows := inventory.get_item_comparison(candidate, old)
|
||||||
|
var deltas := {}
|
||||||
|
for row in rows:
|
||||||
|
deltas[row["key"]] = row["delta"]
|
||||||
|
assert(is_equal_approx(deltas["max_shields"], 1.0))
|
||||||
|
var weapon: ItemInstance = inventory.weapon_slots[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["energy_regeneration"], 2.0))
|
||||||
|
assert(inventory.get_item_comparison(old, old).is_empty())
|
||||||
|
assert(inventory.get_item_comparison(candidate, null)[0]["delta"] == 3.0)
|
||||||
|
assert(ship.get("max_hull") == hull_before and ship.get("max_shields") == shields_before)
|
||||||
|
assert(inventory.module_slots[0] == old and inventory.cargo.has(candidate))
|
||||||
|
# Percentage bonuses combine with flat stats and the rest of the equipment.
|
||||||
|
old.additional_modifiers.append(_modifier("shield_percent", 10.0))
|
||||||
|
candidate.additional_modifiers.append(_modifier("shield_percent", 5.0))
|
||||||
|
var armor := ItemInstance.new()
|
||||||
|
armor.definition = preload("res://resources/items/hull_plating.tres")
|
||||||
|
armor.additional_modifiers.append(_modifier("shield_percent", 20.0))
|
||||||
|
assert(inventory.add_item(armor))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(armor), "module", 1))
|
||||||
|
var expected: float = (float(ship.get("base_max_shields")) + 3.0) * 1.25 - (float(ship.get("base_max_shields")) + 2.0) * 1.3
|
||||||
|
var predicted := 0.0
|
||||||
|
for row in inventory.get_item_comparison(candidate, old):
|
||||||
|
if row["key"] == "max_shields":
|
||||||
|
predicted = row["delta"]
|
||||||
|
assert(is_equal_approx(predicted, expected))
|
||||||
|
var current_shields: float = ship.get("max_shields")
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(candidate), "module", 0))
|
||||||
|
assert(is_equal_approx(float(ship.get("max_shields")) - current_shields, predicted))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(old), "module", 0))
|
||||||
|
assert(inventory.move_item("module", 1, "cargo", inventory.cargo.find(null)))
|
||||||
|
old.additional_modifiers.pop_back()
|
||||||
|
candidate.additional_modifiers.pop_back()
|
||||||
|
inventory._recalculate_ship_stats()
|
||||||
|
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(240, 80)
|
||||||
|
var columns := tooltip.get_child(0)
|
||||||
|
assert(columns.get_child_count() == 3)
|
||||||
|
var comparison: RichTextLabel = columns.get_child(2)
|
||||||
|
assert(comparison.get_parsed_text().contains("Tarcze: +1.00 pkt"))
|
||||||
|
assert(comparison.get_parsed_text().contains("Śr. obrażenia [LPM]:"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("→"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("%"))
|
||||||
|
assert(not comparison.get_parsed_text().contains("p.p."))
|
||||||
|
assert(comparison.get_parsed_text().contains("Regeneracja tarcz: -1.00 pkt/s"))
|
||||||
|
var debug: Label = hud.get_node("DebugScroll/DebugInfo")
|
||||||
|
assert(debug.get_theme_font("font").get_height(10) + debug.get_theme_constant("line_spacing") <= 13.0)
|
||||||
|
await get_tree().process_frame
|
||||||
|
await get_tree().process_frame
|
||||||
|
assert(tooltip.size.x < 1280 and tooltip.size.y < 620)
|
||||||
|
assert(debug.get_line_count() <= 26)
|
||||||
|
assert(debug.get_combined_minimum_size().y < 400)
|
||||||
|
print("EQUIPMENT_COMPARISON_TEST: PASS primary difference, addon loss, duplicate addon sum, regeneration scaling, empty slot, unchanged stats, side column, compact debug, actual percentage effects match equipping")
|
||||||
1
tests/items/equipment_comparison_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dwm652b3w5oli
|
||||||
4
tests/items/equipment_comparison_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/items/equipment_comparison_test.gd" id="1"]
|
||||||
|
[node name="EquipmentComparisonTest" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
39
tests/items/item_icons_test.gd
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
extends Node
|
||||||
|
const GAME := preload("res://scenes/game/game.tscn")
|
||||||
|
const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
||||||
|
|
||||||
|
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")
|
||||||
|
for definition in GENERATOR.DEFINITIONS:
|
||||||
|
assert(definition.icon != null)
|
||||||
|
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"]:
|
||||||
|
assert(inventory.add_item(GENERATOR.generate_for_definition(definition, 8)))
|
||||||
|
var category_index := ShipInventory.MODULE_CATEGORIES.find(definition.category)
|
||||||
|
if category_index >= 0 and inventory.module_slots[category_index] == null:
|
||||||
|
var item := GENERATOR.generate_for_definition(definition, 8)
|
||||||
|
assert(inventory.add_item(item))
|
||||||
|
assert(inventory.move_item("cargo", inventory.cargo.find(item), "module", category_index))
|
||||||
|
var hud := game.get_node("HUD")
|
||||||
|
hud._toggle_inventory()
|
||||||
|
await get_tree().create_timer(0.3).timeout
|
||||||
|
var slots: Array = hud.inventory_panel.get_node("Contents/CargoGrid").get_children()
|
||||||
|
for slot in slots:
|
||||||
|
assert(is_equal_approx(slot.size.x, slot.size.y))
|
||||||
|
var item := inventory.get_item("cargo", slot.slot_index)
|
||||||
|
if item != null:
|
||||||
|
assert(slot.get_node("ItemIcon").texture == item.definition.icon)
|
||||||
|
assert(not slot.get_node("SlotLabel").visible)
|
||||||
|
var style: StyleBoxFlat = slot.get_theme_stylebox("panel")
|
||||||
|
assert(style.bg_color == item.get_background_color())
|
||||||
|
assert(style.border_color == item.get_type_color())
|
||||||
|
print("ITEM_ICONS_TEST: PASS square textures and slots, icon assignment, rarity backgrounds and borders, inventory and equipment")
|
||||||
1
tests/items/item_icons_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://b1agw2jj0ncwg
|
||||||
4
tests/items/item_icons_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/items/item_icons_test.gd" id="1"]
|
||||||
|
[node name="ItemIconsTest" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
@ -22,10 +22,10 @@ func _ready() -> void:
|
|||||||
var laser := GENERATOR.generate_for_definition(preload("res://resources/items/beam_laser.tres"), 5)
|
var laser := GENERATOR.generate_for_definition(preload("res://resources/items/beam_laser.tres"), 5)
|
||||||
assert(inventory.add_item(laser))
|
assert(inventory.add_item(laser))
|
||||||
assert(inventory.move_item("cargo", inventory.cargo.find(laser), "weapon", 0))
|
assert(inventory.move_item("cargo", inventory.cargo.find(laser), "weapon", 0))
|
||||||
# Five separate level-5 regeneration affixes, on five ordinary hull modules.
|
# Five separate level-5 regeneration affixes, on the five equipment categories.
|
||||||
for index in 5:
|
for index in 5:
|
||||||
var module := ItemInstance.new()
|
var module := ItemInstance.new()
|
||||||
module.definition = preload("res://resources/items/hull_plating.tres")
|
module.definition = [preload("res://resources/items/reinforced_shield.tres"), preload("res://resources/items/hull_plating.tres"), preload("res://resources/items/engine_extension.tres"), preload("res://resources/items/compact_generator.tres"), preload("res://resources/items/ship_computer.tres")][index]
|
||||||
module.item_level = 5
|
module.item_level = 5
|
||||||
var addon := ItemStatModifier.new()
|
var addon := ItemStatModifier.new()
|
||||||
addon.affix = REGEN
|
addon.affix = REGEN
|
||||||
|
|||||||
@ -36,7 +36,7 @@ func _ready() -> void:
|
|||||||
addon.value = addon.affix.roll_value(1)
|
addon.value = addon.affix.roll_value(1)
|
||||||
module.additional_modifiers.append(addon)
|
module.additional_modifiers.append(addon)
|
||||||
assert(inventory.add_item(module))
|
assert(inventory.add_item(module))
|
||||||
assert(inventory.move_item("cargo", inventory.cargo.find(module), "module", 0))
|
assert(inventory.move_item("cargo", inventory.cargo.find(module), "module", 2))
|
||||||
assert(ship.get("shield_on_damage_percent") == 1.0)
|
assert(ship.get("shield_on_damage_percent") == 1.0)
|
||||||
var indicator := Node2D.new()
|
var indicator := Node2D.new()
|
||||||
indicator.set_script(preload("res://scripts/game/ship_energy_indicator.gd"))
|
indicator.set_script(preload("res://scripts/game/ship_energy_indicator.gd"))
|
||||||
|
|||||||
@ -20,7 +20,7 @@ func _ready() -> void:
|
|||||||
module.definition = preload("res://resources/items/engine_extension.tres")
|
module.definition = preload("res://resources/items/engine_extension.tres")
|
||||||
module.additional_modifiers.append(modifier)
|
module.additional_modifiers.append(modifier)
|
||||||
assert(inventory.add_item(module))
|
assert(inventory.add_item(module))
|
||||||
assert(inventory.move_item("cargo", 0, "module", 0))
|
assert(inventory.move_item("cargo", 0, "module", 2))
|
||||||
assert(ship.get("shield_on_damage_percent") == 1.0)
|
assert(ship.get("shield_on_damage_percent") == 1.0)
|
||||||
ship.set("shields", 0.0)
|
ship.set("shields", 0.0)
|
||||||
var enemy := _enemy(ship, 100.0)
|
var enemy := _enemy(ship, 100.0)
|
||||||
@ -53,7 +53,7 @@ func _ready() -> void:
|
|||||||
ship.set("shields", ship.get("max_shields") - 0.1)
|
ship.set("shields", ship.get("max_shields") - 0.1)
|
||||||
enemy.call("take_weapon_hit", 10.0, false)
|
enemy.call("take_weapon_hit", 10.0, false)
|
||||||
assert(ship.get("shields") == ship.get("max_shields"))
|
assert(ship.get("shields") == ship.get("max_shields"))
|
||||||
assert(inventory.move_item("module", 0, "cargo", 0))
|
assert(inventory.move_item("module", 2, "cargo", 0))
|
||||||
inventory.weapon_slots[0].additional_modifiers.clear()
|
inventory.weapon_slots[0].additional_modifiers.clear()
|
||||||
inventory.call("_recalculate_ship_stats")
|
inventory.call("_recalculate_ship_stats")
|
||||||
ship.set("shields", 0.0)
|
ship.set("shields", 0.0)
|
||||||
|
|||||||
64
tests/levels/boss_spawn_test.gd
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
extends Node
|
||||||
|
const GAME := preload("res://scenes/game/game.tscn")
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
GameState.start_new_run()
|
||||||
|
GameState.system_seed = 314159
|
||||||
|
var game := GAME.instantiate()
|
||||||
|
add_child(game)
|
||||||
|
game.set_physics_process(false)
|
||||||
|
var player: CharacterBody2D = game.get_node("PlayerShip")
|
||||||
|
player.set_physics_process(false)
|
||||||
|
player.get_node("WeaponController").set_physics_process(false)
|
||||||
|
var enemies: Array[Node] = []
|
||||||
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||||
|
if game.is_ancestor_of(enemy):
|
||||||
|
assert(enemy.loot_tier != 2)
|
||||||
|
enemy.set_physics_process(false)
|
||||||
|
enemies.append(enemy)
|
||||||
|
assert(enemies.size() == 4)
|
||||||
|
for index in enemies.size() - 1:
|
||||||
|
enemies[index].take_damage(100000.0)
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(game.get_remaining_enemies() == 1 and not game._boss_spawned)
|
||||||
|
# Spawn positions remain clear and at the same distance near map edges.
|
||||||
|
for position in [Vector2.ZERO, Vector2(2500, 1700), Vector2(-2500, 1700), Vector2(2500, -1700), Vector2(-2500, -1700)]:
|
||||||
|
player.position = position
|
||||||
|
var candidate: Vector2 = game._find_boss_spawn_position()
|
||||||
|
assert(is_equal_approx(candidate.distance_to(position), game.BOSS_SPAWN_DISTANCE))
|
||||||
|
assert(absf(candidate.x) <= game.WORLD_SIZE.x * 0.5 - game.BOSS_SPAWN_MARGIN)
|
||||||
|
assert(absf(candidate.y) <= game.WORLD_SIZE.y * 0.5 - game.BOSS_SPAWN_MARGIN)
|
||||||
|
assert(candidate.length() >= 300.0)
|
||||||
|
for planet in game.system_data["planets"]:
|
||||||
|
assert(candidate.distance_to(planet["position"]) >= planet["radius"] + 130.0)
|
||||||
|
player.position = Vector2(700, 500)
|
||||||
|
enemies.back().take_damage(100000.0)
|
||||||
|
player.set("_is_destroyed", true)
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(not game._boss_spawned)
|
||||||
|
player.set("_is_destroyed", false)
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(game._boss_spawned and game.get_remaining_enemies() == 1)
|
||||||
|
assert(not game.system_cleared and not game.services_menu.visible)
|
||||||
|
var boss: CharacterBody2D
|
||||||
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||||
|
if game.is_ancestor_of(enemy) and enemy.loot_tier == 2:
|
||||||
|
assert(boss == null)
|
||||||
|
boss = enemy
|
||||||
|
assert(boss != null)
|
||||||
|
boss.set_physics_process(false)
|
||||||
|
assert(is_equal_approx(boss.position.distance_to(player.position), game.BOSS_SPAWN_DISTANCE))
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(game.get_remaining_enemies() == 1)
|
||||||
|
assert(not game.open_wormhole())
|
||||||
|
boss.take_damage(100000.0)
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(game.system_cleared and game.get_remaining_enemies() == 0)
|
||||||
|
game._physics_process(0.0)
|
||||||
|
assert(game.get_remaining_enemies() == 0)
|
||||||
|
for definition in preload("res://scripts/items/item_generator.gd").DEFINITIONS:
|
||||||
|
var category_index := ShipInventory.MODULE_CATEGORIES.find(definition.category)
|
||||||
|
if category_index >= 0:
|
||||||
|
assert(definition.display_name == ShipInventory.MODULE_NAMES[category_index])
|
||||||
|
print("BOSS_SPAWN_TEST: PASS delayed boss, elites, no early completion, distance, safe placement, single spawn, dead player, item names")
|
||||||
|
get_tree().quit()
|
||||||