Compare commits
No commits in common. "9808a03d13b21536c6af95fc2e478464dd414e25" and "24a58b60db0631e5fb0c8d5a77810b1b2daa5c88" have entirely different histories.
9808a03d13
...
24a58b60db
|
Before Width: | Height: | Size: 1.9 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bgs1htiuvgmic"
|
||||
path="res://.godot/imported/gamma.png-96d3080e05fe2aad0fc3e1de127f7d0d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/gamma.png"
|
||||
dest_files=["res://.godot/imported/gamma.png-96d3080e05fe2aad0fc3e1de127f7d0d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@ -1,10 +0,0 @@
|
||||
# Działko gamma
|
||||
|
||||
Generated with the built-in image_gen tool.
|
||||
|
||||
Style reference: `assets/icons/plasma.png`.
|
||||
Output: `assets/icons/gamma.png`, transparent background.
|
||||
|
||||
## Prompt
|
||||
|
||||
Create a production-quality square game inventory icon for a spaceship GAMMA CANNON, matching the supplied plasma-cannon reference's detailed metallic 3D science-fiction rendering, three-quarter isometric view and crisp strong silhouette. Reference image is for style and perspective only. Design a DIFFERENT distinct weapon: compact heavy orbital gamma emitter with layered gunmetal and brushed silver shielding plates, dark mechanical rear mount, a broad circular emitter muzzle facing lower right, a bright lime-green irradiated spherical core contained between three radial containment prongs, a few small orbiting green particles within the muzzle, luminous green coolant conduits and small restrained brass accents. Industrial believable spaceship-mounted turret, no pistol handle. Radiation aesthetic in green, no purple plasma. The cannon alone occupies 85 percent of the square, centered, all parts fully in frame, no cropped extremities. Readable at 48px thumbnail, bold broad shapes and controlled highlights, no background scene, no border, no labels, no lettering, no text. Genuine transparent background and clean alpha edges, no ground or drop shadow. Single isolated icon.
|
||||
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96"><defs><radialGradient id="g"><stop stop-color="#edffd0"/><stop offset=".5" stop-color="#80ff45"/><stop offset="1" stop-color="#174823"/></radialGradient></defs><path d="M27 80V47L34 24H62L69 47V80Z" fill="#293e46" stroke="#95b7ad" stroke-width="3"/><path d="M38 60V18H58V60" fill="#11241a" stroke="#59d44c" stroke-width="3"/><circle cx="48" cy="25" r="17" fill="url(#g)"/><ellipse cx="48" cy="25" rx="25" ry="10" fill="none" stroke="#b7ff72" stroke-width="2" transform="rotate(-35 48 25)"/><circle cx="65" cy="10" r="3" fill="#e0ffc3"/><path d="M34 68H62M34 74H62" stroke="#7eff4f" stroke-width="3"/></svg>
|
||||
|
Before Width: | Height: | Size: 689 B |
@ -1,43 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b30nivtfvxw31"
|
||||
path="res://.godot/imported/gamma.svg-877dc4511099b181b72b5bbafe97b7fd.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/gamma.svg"
|
||||
dest_files=["res://.godot/imported/gamma.svg-877dc4511099b181b72b5bbafe97b7fd.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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ooii0cnkunnb"
|
||||
path="res://.godot/imported/aluminium.png-63588dbb597f01d62b3f0366767573a6.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/aluminium.png"
|
||||
dest_files=["res://.godot/imported/aluminium.png-63588dbb597f01d62b3f0366767573a6.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bvxxyh35g4qgh"
|
||||
path="res://.godot/imported/ammunition.png-55b812a61f21303b828ce907b57955d0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/ammunition.png"
|
||||
dest_files=["res://.godot/imported/ammunition.png-55b812a61f21303b828ce907b57955d0.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 2.0 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bt0ve4g2lbcxc"
|
||||
path="res://.godot/imported/iron.png-9f0bab611f228be580c28e352ca1d8cc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/iron.png"
|
||||
dest_files=["res://.godot/imported/iron.png-9f0bab611f228be580c28e352ca1d8cc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 1.5 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bwg8xyrhjg2ql"
|
||||
path="res://.godot/imported/irradiated_ammunition.png-43f90162db35d57c3d57de6de22435e4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/irradiated_ammunition.png"
|
||||
dest_files=["res://.godot/imported/irradiated_ammunition.png-43f90162db35d57c3d57de6de22435e4.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 988 KiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ns3mapyv4n2g"
|
||||
path="res://.godot/imported/missile.png-d91a6d6e7348b7fba50d4cc3ac087245.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/missile.png"
|
||||
dest_files=["res://.godot/imported/missile.png-d91a6d6e7348b7fba50d4cc3ac087245.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 1.7 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b1gltl1goxq3a"
|
||||
path="res://.godot/imported/parts.png-f14343f401c851f9b669606251dc7106.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/parts.png"
|
||||
dest_files=["res://.godot/imported/parts.png-f14343f401c851f9b669606251dc7106.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@ -1,46 +0,0 @@
|
||||
{
|
||||
"tool": "built-in image_gen",
|
||||
"transparent_background": true,
|
||||
"prompts": [
|
||||
{
|
||||
"key": "iron",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a rugged dark graphite-gray iron ore nugget with a few rusty orange seams and raw crystalline metallic facets, clearly a mined mineral",
|
||||
"asset": "assets/icons/resources/iron.png"
|
||||
},
|
||||
{
|
||||
"key": "titanium",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a chunky cool blue-gray titanium ore crystal with silver-blue metallic facets and pale blue edge highlights, clearly different from iron",
|
||||
"asset": "assets/icons/resources/titanium.png"
|
||||
},
|
||||
{
|
||||
"key": "aluminium",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: two small stacked refined aluminium ingots, bright matte silvery metal, pale cool white reflections, clean beveled edges",
|
||||
"asset": "assets/icons/resources/aluminium.png"
|
||||
},
|
||||
{
|
||||
"key": "uranium",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a rugged uranium ore chunk, dark stone with luminous toxic lime-green mineral veins and tiny green crystal inclusions, unmistakable radiation resource",
|
||||
"asset": "assets/icons/resources/uranium.png"
|
||||
},
|
||||
{
|
||||
"key": "parts",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a compact cluster of mechanical salvage parts: one steel gear, one brass bearing and a small bent circuit board, bold readable silhouette",
|
||||
"asset": "assets/icons/resources/parts.png"
|
||||
},
|
||||
{
|
||||
"key": "ammunition",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: three short brass-cased autocannon cartridges with metallic copper tips, grouped neatly, one cartridge slightly taller",
|
||||
"asset": "assets/icons/resources/ammunition.png"
|
||||
},
|
||||
{
|
||||
"key": "irradiated_ammunition",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: two futuristic gamma cannon ammunition capsules: armored dark steel cylindrical casings, small containment bands and luminous lime-green sealed cores, no conventional bullets",
|
||||
"asset": "assets/icons/resources/irradiated_ammunition.png"
|
||||
},
|
||||
{
|
||||
"key": "missile",
|
||||
"prompt": "Generate one high-quality isolated game inventory resource icon. Square image with a genuine transparent background. Detailed stylized 3D science-fiction game item render, crisp metal and mineral materials, broad readable silhouette, three-quarter view, controlled highlights. Center the object with 12 percent transparent padding on all sides; keep every part completely inside the frame. Must read clearly as a 32px HUD icon. No scene, no floor, no drop shadow, no border, no text, no lettering, no labels. Subject: a single compact spaceship missile with pointed silver nose, dark steel casing, two small red fins and a restrained orange rear nozzle, diagonal three-quarter view",
|
||||
"asset": "assets/icons/resources/missile.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.0 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://e3hyjgddtws3"
|
||||
path="res://.godot/imported/titanium.png-0b4998bc95056c5a7906568e449b30ff.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/titanium.png"
|
||||
dest_files=["res://.godot/imported/titanium.png-0b4998bc95056c5a7906568e449b30ff.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
Before Width: | Height: | Size: 2.1 MiB |
@ -1,40 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b6enhdjvecuep"
|
||||
path="res://.godot/imported/uranium.png-ceac43be56616b10258ea19f379a1280.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/icons/resources/uranium.png"
|
||||
dest_files=["res://.godot/imported/uranium.png-ceac43be56616b10258ea19f379a1280.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@ -1,4 +1,4 @@
|
||||
[gd_resource type="Resource" script_class="ItemAffixDatabase" load_steps=18 format=3]
|
||||
[gd_resource type="Resource" script_class="ItemAffixDatabase" load_steps=15 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/items/item_affix_database.gd" id="1_database"]
|
||||
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="2_type"]
|
||||
@ -17,10 +17,6 @@
|
||||
|
||||
[ext_resource type="Resource" path="res://resources/items/affixes/shield_on_damage.tres" id="14_affix"]
|
||||
|
||||
[ext_resource type="Resource" path="res://resources/items/affixes/kinetic_absorption.tres" id="kinetic"]
|
||||
[ext_resource type="Resource" path="res://resources/items/affixes/energy_absorption.tres" id="energy"]
|
||||
[ext_resource type="Resource" path="res://resources/items/affixes/radiation_absorption.tres" id="radiation"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_database")
|
||||
affixes = Array[ExtResource("2_type")]([ExtResource("3_affix"), ExtResource("4_affix"), ExtResource("5_affix"), ExtResource("6_affix"), ExtResource("7_affix"), ExtResource("8_affix"), ExtResource("9_affix"), ExtResource("10_affix"), ExtResource("11_affix"), ExtResource("12_affix"), ExtResource("13_affix"), ExtResource("14_affix"), ExtResource("kinetic"), ExtResource("energy"), ExtResource("radiation")])
|
||||
affixes = Array[ExtResource("2_type")]([ExtResource("3_affix"), ExtResource("4_affix"), ExtResource("5_affix"), ExtResource("6_affix"), ExtResource("7_affix"), ExtResource("8_affix"), ExtResource("9_affix"), ExtResource("10_affix"), ExtResource("11_affix"), ExtResource("12_affix"), ExtResource("13_affix"), ExtResource("14_affix")])
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="ItemAffixDefinition" load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="1"]
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
affix_id = "energy_absorption"
|
||||
display_name = "Absorpcja obrażeń energetycznych"
|
||||
stat_key = "energy_absorption"
|
||||
description = "Niweluje obrażenia tego typu przed tarczą i pancerzem. Łączny limit statku: 60%."
|
||||
category_mask = 95
|
||||
minimum_value_level_1 = 1.0
|
||||
maximum_value_level_1 = 1.0
|
||||
minimum_value_level_1000 = 10.0
|
||||
maximum_value_level_1000 = 15.0
|
||||
@ -1,13 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="ItemAffixDefinition" load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="1"]
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
affix_id = "kinetic_absorption"
|
||||
display_name = "Absorpcja obrażeń kinetycznych"
|
||||
stat_key = "kinetic_absorption"
|
||||
description = "Niweluje obrażenia tego typu przed tarczą i pancerzem. Łączny limit statku: 60%."
|
||||
category_mask = 95
|
||||
minimum_value_level_1 = 1.0
|
||||
maximum_value_level_1 = 1.0
|
||||
minimum_value_level_1000 = 10.0
|
||||
maximum_value_level_1000 = 15.0
|
||||
@ -1,13 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="ItemAffixDefinition" load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="1"]
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
affix_id = "radiation_absorption"
|
||||
display_name = "Absorpcja obrażeń radiacyjnych"
|
||||
stat_key = "radiation_absorption"
|
||||
description = "Niweluje obrażenia tego typu przed tarczą i pancerzem. Łączny limit statku: 60%."
|
||||
category_mask = 95
|
||||
minimum_value_level_1 = 1.0
|
||||
maximum_value_level_1 = 1.0
|
||||
minimum_value_level_1000 = 10.0
|
||||
maximum_value_level_1000 = 15.0
|
||||
@ -1,21 +0,0 @@
|
||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=3 format=3]
|
||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1"]
|
||||
[ext_resource type="Texture2D" path="res://assets/icons/gamma.png" id="icon"]
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
icon = ExtResource("icon")
|
||||
item_id = "gamma_cannon"
|
||||
display_name = "Działko gamma"
|
||||
category = 0
|
||||
description = "Radiacyjna kula. Napromieniowanie: 3 s, 25% obrażeń trafienia/s. Kolejne trafienia odświeżają czas. Zużywa napromieniowaną amunicję."
|
||||
primary_stat = "damage"
|
||||
primary_value = 15.0
|
||||
stat_suffix = " DMG"
|
||||
weapon_kind = 4
|
||||
fire_interval = 0.8
|
||||
projectile_speed = 430.0
|
||||
weapon_range = 800.0
|
||||
damage_lower_roll_min = 10
|
||||
damage_lower_roll_max = 14
|
||||
damage_spread_roll_min = 4
|
||||
damage_spread_roll_max = 8
|
||||
@ -1,16 +1,6 @@
|
||||
[gd_resource type="Theme" load_steps=3 format=3]
|
||||
[gd_resource type="Theme" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="FontFile" path="res://assets/fonts/font2.ttf" id="1_font"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="TooltipShell"]
|
||||
bg_color = Color(0.035, 0.055, 0.085, 1)
|
||||
content_margin_left = 2.0
|
||||
content_margin_top = 2.0
|
||||
content_margin_right = 2.0
|
||||
content_margin_bottom = 2.0
|
||||
shadow_size = 0
|
||||
|
||||
[resource]
|
||||
default_font = ExtResource("1_font")
|
||||
TooltipPanel/styles/panel = SubResource("TooltipShell")
|
||||
TooltipLabel/font_sizes/font_size = 11
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
[ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="PanelStyle"]
|
||||
bg_color = Color(0.045, 0.075, 0.11, 0.64)
|
||||
bg_color = Color(0.045, 0.075, 0.11, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
|
||||
@ -43,7 +43,7 @@ text = "SYSTEMY POKŁADOWE"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="EquipmentLayout" type="Control" parent="Contents"]
|
||||
custom_minimum_size = Vector2(284, 552)
|
||||
custom_minimum_size = Vector2(284, 456)
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
@ -100,9 +100,9 @@ overlay_slot = true
|
||||
[node name="Module2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 14.0
|
||||
offset_top = 200.0
|
||||
offset_top = 178.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 264.0
|
||||
offset_bottom = 242.0
|
||||
slot_kind = "module"
|
||||
slot_index = 1
|
||||
overlay_slot = true
|
||||
@ -110,9 +110,9 @@ overlay_slot = true
|
||||
[node name="Module3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 14.0
|
||||
offset_top = 292.0
|
||||
offset_top = 248.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 356.0
|
||||
offset_bottom = 312.0
|
||||
slot_kind = "module"
|
||||
slot_index = 2
|
||||
overlay_slot = true
|
||||
@ -120,9 +120,9 @@ overlay_slot = true
|
||||
[node name="Module4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 14.0
|
||||
offset_top = 384.0
|
||||
offset_top = 318.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 448.0
|
||||
offset_bottom = 382.0
|
||||
slot_kind = "module"
|
||||
slot_index = 3
|
||||
overlay_slot = true
|
||||
@ -130,9 +130,9 @@ overlay_slot = true
|
||||
[node name="Module5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 14.0
|
||||
offset_top = 476.0
|
||||
offset_top = 388.0
|
||||
offset_right = 78.0
|
||||
offset_bottom = 540.0
|
||||
offset_bottom = 452.0
|
||||
slot_kind = "module"
|
||||
slot_index = 4
|
||||
overlay_slot = true
|
||||
@ -150,9 +150,9 @@ overlay_slot = true
|
||||
[node name="Extension2" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 206.0
|
||||
offset_top = 200.0
|
||||
offset_top = 178.0
|
||||
offset_right = 270.0
|
||||
offset_bottom = 264.0
|
||||
offset_bottom = 242.0
|
||||
slot_kind = "extension"
|
||||
slot_index = 1
|
||||
overlay_slot = true
|
||||
@ -160,9 +160,9 @@ overlay_slot = true
|
||||
[node name="Extension3" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 206.0
|
||||
offset_top = 292.0
|
||||
offset_top = 248.0
|
||||
offset_right = 270.0
|
||||
offset_bottom = 356.0
|
||||
offset_bottom = 312.0
|
||||
slot_kind = "extension"
|
||||
slot_index = 2
|
||||
overlay_slot = true
|
||||
@ -170,9 +170,9 @@ overlay_slot = true
|
||||
[node name="Extension4" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 206.0
|
||||
offset_top = 384.0
|
||||
offset_top = 318.0
|
||||
offset_right = 270.0
|
||||
offset_bottom = 448.0
|
||||
offset_bottom = 382.0
|
||||
slot_kind = "extension"
|
||||
slot_index = 3
|
||||
overlay_slot = true
|
||||
@ -180,9 +180,9 @@ overlay_slot = true
|
||||
[node name="Extension5" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||
layout_mode = 0
|
||||
offset_left = 206.0
|
||||
offset_top = 476.0
|
||||
offset_top = 388.0
|
||||
offset_right = 270.0
|
||||
offset_bottom = 540.0
|
||||
offset_bottom = 452.0
|
||||
slot_kind = "extension"
|
||||
slot_index = 4
|
||||
overlay_slot = true
|
||||
|
||||
@ -49,6 +49,16 @@ layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "ZAMKNIJ"
|
||||
|
||||
[node name="Ammunition" type="HBoxContainer" parent="Contents"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 12
|
||||
|
||||
[node name="Count" type="Label" parent="Contents/Ammunition"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "AMUNICJA: 50"
|
||||
|
||||
[node name="CargoGrid" type="GridContainer" parent="Contents"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
|
||||
@ -7,7 +7,7 @@ const BALANCE := preload("res://scripts/captain/captain_balance.gd")
|
||||
@export var experience: int = 0
|
||||
@export var credits: int = 0
|
||||
@export var parts: float = 0.0
|
||||
@export var minerals: Dictionary = {"uranium": 0, "titanium": 0, "iron": 0, "aluminium": 0}
|
||||
@export var minerals: Dictionary = {"titanium": 0, "iron": 0, "aluminium": 0}
|
||||
@export var learning_points: int = 0
|
||||
@export var skills: Dictionary = {
|
||||
"piloting": 0, "gunner": 0, "mechanic": 0, "sharp_eye": 0,
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
extends RefCounted
|
||||
class_name DamageTypes
|
||||
|
||||
enum Type { KINETIC, ENERGY, RADIATION }
|
||||
const KEYS := ["kinetic_absorption", "energy_absorption", "radiation_absorption"]
|
||||
const NAMES := ["Kinetyczne", "Energetyczne", "Radiacyjne"]
|
||||
|
||||
static func for_weapon(kind: int) -> int:
|
||||
if kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
return Type.RADIATION
|
||||
if kind in [ItemDefinition.WeaponKind.LASER, ItemDefinition.WeaponKind.PLASMA]:
|
||||
return Type.ENERGY
|
||||
return Type.KINETIC
|
||||
|
||||
static func capped(values: Vector3) -> Vector3:
|
||||
values = values.max(Vector3.ZERO)
|
||||
var total := values.x + values.y + values.z
|
||||
return values * (60.0 / total) if total > 60.0 else values
|
||||
|
||||
static func enemy_profile(level: int, seed_value: int) -> Dictionary:
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = seed_value
|
||||
var weights := Vector3(rng.randf_range(0.1, 1.0), rng.randf_range(0.1, 1.0), rng.randf_range(0.1, 1.0))
|
||||
var total := lerpf(2.0, 60.0, pow(float(clampi(level, 1, 1000) - 1) / 999.0, 1.25))
|
||||
return {"kind": rng.randi_range(0, 4), "absorption": weights * total / (weights.x + weights.y + weights.z)}
|
||||
|
||||
static func describe(values: Vector3) -> String:
|
||||
return "Absorpcja: K %.1f%% · E %.1f%% · R %.1f%%" % [values.x, values.y, values.z]
|
||||
@ -1 +0,0 @@
|
||||
uid://cumj03bmuxvlr
|
||||
@ -46,7 +46,5 @@ func _draw() -> void:
|
||||
var background := Rect2(-width * 0.5, -3.0, width, 6.0)
|
||||
draw_rect(background.grow(1.0), Color("08111dee"))
|
||||
draw_rect(background, Color("39232bee"))
|
||||
draw_rect(Rect2(-width * 0.5, 5.0, width, 3.0), Color("142a3d"))
|
||||
draw_rect(Rect2(-width * 0.5, 5.0, width * clampf(enemy.shields / maxf(1.0, enemy.max_shields), 0.0, 1.0), 3.0), Color("67cfff"))
|
||||
var color := _tier_color()
|
||||
draw_rect(Rect2(background.position, Vector2(width * get_health_ratio(), 6.0)), color)
|
||||
|
||||
@ -49,8 +49,5 @@ func _hit_target(target: Variant) -> void:
|
||||
get_parent().add_child(effect)
|
||||
effect.call("configure", false, Color(1.0, 0.32, 0.38))
|
||||
if target is Node and target.has_method("take_damage"):
|
||||
if target is CharacterBody2D:
|
||||
target.call("take_damage", damage, false, DamageTypes.Type.ENERGY)
|
||||
else:
|
||||
target.call("take_damage", damage)
|
||||
target.call("take_damage", damage)
|
||||
queue_free()
|
||||
|
||||
@ -2,14 +2,12 @@ extends CharacterBody2D
|
||||
|
||||
const DAMAGE_POPUP_SCENE := preload("res://scenes/game/damage_popup.tscn")
|
||||
const IMPACT_EFFECT_SCENE := preload("res://scenes/game/impact_effect.tscn")
|
||||
const PLASMA_PROJECTILE_SCENE := preload("res://scenes/game/enemy_plasma_projectile.tscn")
|
||||
const WEAPON_AUDIO_SCRIPT := preload("res://scripts/game/weapon_audio.gd")
|
||||
const ITEM_GENERATOR := preload("res://scripts/items/item_generator.gd")
|
||||
const LOOT_PICKUP := preload("res://scripts/items/loot_pickup.gd")
|
||||
const LOOT_OFFSET := Vector2(0, 36)
|
||||
const LEVEL_BALANCE := preload("res://scripts/levels/level_balance.gd")
|
||||
const LASER_COOLDOWN_MULTIPLIER := 2.0
|
||||
const LASER_MINIMUM_COOLDOWN := 1.4
|
||||
const LASER_MISS_CHANCE := 0.35
|
||||
|
||||
@export_enum("Normal", "Elite", "Boss") var loot_tier: int = 0
|
||||
|
||||
@ -22,12 +20,6 @@ const LASER_MISS_CHANCE := 0.35
|
||||
@export var weapon_cooldown := 1.5
|
||||
@export var weapon_damage := 8.0
|
||||
|
||||
var max_shields := 20.0
|
||||
var shields := 20.0
|
||||
var absorption := Vector3.ZERO
|
||||
var weapon_kind := ItemDefinition.WeaponKind.PLASMA
|
||||
var _shield_visual: Node2D
|
||||
|
||||
var hull := 50.0
|
||||
var _player: CharacterBody2D
|
||||
var _activated := false
|
||||
@ -37,13 +29,8 @@ var _weapon_timer := 0.0
|
||||
func _ready() -> void:
|
||||
hull = max_hull
|
||||
_sprite = $Sprite2D
|
||||
_shield_visual = Node2D.new()
|
||||
_shield_visual.set_script(preload("res://scripts/game/shield_visual.gd"))
|
||||
_shield_visual.scale = Vector2.ONE * get_visual_size() / 64.0
|
||||
add_child(_shield_visual)
|
||||
_shield_visual.set_shield_values(shields, max_shields)
|
||||
add_to_group("enemies")
|
||||
_weapon_timer = randf_range(0.2, get_fire_interval())
|
||||
_weapon_timer = randf_range(0.2, weapon_cooldown)
|
||||
|
||||
func apply_level_settings(level: int, tier: int) -> void:
|
||||
loot_tier = tier
|
||||
@ -55,11 +42,6 @@ func apply_level_settings(level: int, tier: int) -> void:
|
||||
var damage_bonus := 4.0 if tier == 2 else (1.3 if tier == 1 else 1.0)
|
||||
max_hull = 50.0 * power * hull_multiplier * combat_multiplier
|
||||
hull = max_hull
|
||||
max_shields = max_hull * 0.4
|
||||
shields = max_shields
|
||||
var profile := DamageTypes.enemy_profile(level, GameState.system_seed)
|
||||
weapon_kind = int(profile["kind"])
|
||||
absorption = profile["absorption"]
|
||||
weapon_damage = 8.0 * power * damage_bonus * combat_multiplier
|
||||
approach_speed = 62.0 * (1.0 + 0.0005 * (clampi(level, 1, 1000) - 1)) * boss_multiplier
|
||||
approach_acceleration = 85.0 * boss_multiplier
|
||||
@ -68,9 +50,6 @@ func apply_level_settings(level: int, tier: int) -> void:
|
||||
weapon_range = 680.0 * boss_multiplier
|
||||
weapon_cooldown = maxf(0.55, 1.5 / (1.0 + 0.001 * (clampi(level, 1, 1000) - 1))) / boss_multiplier
|
||||
$CollisionShape2D.scale = Vector2.ONE * boss_multiplier
|
||||
if is_instance_valid(_shield_visual):
|
||||
_shield_visual.scale = Vector2.ONE * get_visual_size() / 64.0
|
||||
_shield_visual.set_shield_values(shields, max_shields)
|
||||
|
||||
func configure(player: CharacterBody2D, ship_texture: Texture2D) -> void:
|
||||
_player = player
|
||||
@ -105,7 +84,7 @@ func _physics_process(delta: float) -> void:
|
||||
_weapon_timer = maxf(0.0, _weapon_timer - delta)
|
||||
if to_player.length() <= weapon_range and _weapon_timer <= 0.0:
|
||||
_fire_plasma(direction)
|
||||
_weapon_timer = get_fire_interval()
|
||||
_weapon_timer = weapon_cooldown
|
||||
else:
|
||||
velocity = velocity.move_toward(Vector2.ZERO, approach_acceleration * delta)
|
||||
|
||||
@ -119,77 +98,31 @@ func _check_player_collision() -> void:
|
||||
_player.call("register_enemy_collision", global_position)
|
||||
|
||||
func _fire_plasma(direction: Vector2) -> void:
|
||||
var muzzle := global_position + direction * (get_visual_size() * 0.5 + 8.0)
|
||||
if weapon_kind == ItemDefinition.WeaponKind.LASER:
|
||||
var endpoint := muzzle + _laser_aim_direction(direction) * weapon_range
|
||||
var query := PhysicsRayQueryParameters2D.create(muzzle, endpoint, 3, [get_rid()])
|
||||
var hit := get_world_2d().direct_space_state.intersect_ray(query)
|
||||
if not hit.is_empty():
|
||||
endpoint = hit["position"]
|
||||
var target: Node = hit.get("collider")
|
||||
if target is CharacterBody2D and target.has_method("take_damage"):
|
||||
target.take_damage(weapon_damage, false, DamageTypes.Type.ENERGY)
|
||||
var beam := Line2D.new()
|
||||
beam.set_script(preload("res://scripts/game/laser_beam_visual.gd"))
|
||||
beam.width = 4.0
|
||||
beam.default_color = Color(1.0, 0.3, 0.3)
|
||||
beam.add_point(muzzle)
|
||||
beam.add_point(endpoint)
|
||||
get_parent().add_child(beam)
|
||||
get_tree().create_timer(0.1).timeout.connect(beam.queue_free)
|
||||
else:
|
||||
var projectile := preload("res://scenes/game/weapon_projectile.tscn").instantiate()
|
||||
projectile.enemy_shot = true
|
||||
projectile.collision_mask = 3
|
||||
projectile.missile_homing = false
|
||||
var speed := 430.0 if weapon_kind == ItemDefinition.WeaponKind.GAMMA else (950.0 if weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN else 600.0)
|
||||
projectile.configure(muzzle, direction, weapon_kind, speed, weapon_damage, weapon_range)
|
||||
get_parent().add_child(projectile)
|
||||
WEAPON_AUDIO_SCRIPT.play(get_parent(), global_position, weapon_kind, -4.0)
|
||||
var projectile := PLASMA_PROJECTILE_SCENE.instantiate() as Area2D
|
||||
projectile.call("configure", global_position + direction * (get_visual_size() * 0.5), direction, weapon_damage)
|
||||
get_parent().add_child(projectile)
|
||||
# Relative to the Plasma bus: enemy shots are 4 dB quieter than player shots.
|
||||
WEAPON_AUDIO_SCRIPT.play(get_parent(), global_position, ItemDefinition.WeaponKind.PLASMA, -4.0)
|
||||
|
||||
func take_weapon_hit(amount: float, critical: bool, damage_type: int = DamageTypes.Type.KINETIC) -> void:
|
||||
if is_queued_for_deletion() or hull <= 0.0:
|
||||
return
|
||||
var before := hull + shields
|
||||
take_damage(amount, critical, damage_type)
|
||||
func take_weapon_hit(amount: float, critical: bool) -> void:
|
||||
var actual_damage := minf(maxf(0.0, amount), maxf(0.0, hull))
|
||||
if is_queued_for_deletion():
|
||||
actual_damage = 0.0
|
||||
take_damage(amount, critical)
|
||||
if is_instance_valid(_player):
|
||||
_player.call("restore_shields_from_damage", maxf(0.0, before - hull - shields))
|
||||
_player.call("restore_shields_from_damage", actual_damage)
|
||||
|
||||
func take_damage(amount: float, critical: bool = false, damage_type: int = DamageTypes.Type.KINETIC) -> void:
|
||||
func take_damage(amount: float, critical: bool = false) -> void:
|
||||
if is_queued_for_deletion() or hull <= 0.0:
|
||||
return
|
||||
var actual := maxf(0.0, amount) * (1.0 - absorption[damage_type] / 100.0)
|
||||
var shield_damage := minf(shields, actual)
|
||||
shields -= shield_damage
|
||||
hull = maxf(0.0, hull - actual + shield_damage)
|
||||
if is_instance_valid(_shield_visual):
|
||||
_shield_visual.set_shield_values(shields, max_shields)
|
||||
if shield_damage > 0.0:
|
||||
_shield_visual.flash_hit()
|
||||
_show_damage_popup(actual, critical)
|
||||
hull = maxf(0.0, hull - maxf(0.0, amount))
|
||||
_show_damage_popup(amount, critical)
|
||||
if hull <= 0.0:
|
||||
_reward_captain()
|
||||
_drop_loot()
|
||||
_spawn_destruction_effect()
|
||||
queue_free()
|
||||
|
||||
func get_fire_interval() -> float:
|
||||
if weapon_kind == ItemDefinition.WeaponKind.LASER:
|
||||
return maxf(LASER_MINIMUM_COOLDOWN, weapon_cooldown * LASER_COOLDOWN_MULTIPLIER)
|
||||
return weapon_cooldown
|
||||
|
||||
func _laser_aim_direction(direction: Vector2) -> Vector2:
|
||||
if randf() < LASER_MISS_CHANCE:
|
||||
var side := Vector2(-direction.y, direction.x)
|
||||
var distance := global_position.distance_to(_player.global_position) if is_instance_valid(_player) else weapon_range
|
||||
var offset := randf_range(60.0, 110.0) * (-1.0 if randf() < 0.5 else 1.0)
|
||||
return (direction * maxf(1.0, distance) + side * offset).normalized()
|
||||
return direction.rotated(randf_range(-0.02, 0.02))
|
||||
|
||||
func get_weapon_dps() -> float:
|
||||
var interval := get_fire_interval()
|
||||
return weapon_damage / maxf(0.001, interval) * (1.0 + 0.25 * minf(3.0, interval) if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0)
|
||||
|
||||
func _reward_captain() -> void:
|
||||
if is_instance_valid(_player):
|
||||
var reward := GameState.captain.reward_enemy(GameState.system_level, loot_tier, float(_player.get("experience_multiplier")), float(_player.get("credits_multiplier")), false)
|
||||
|
||||
@ -19,9 +19,6 @@ var _sidebar_tween: Tween
|
||||
const SIDEBAR_WIDTH := 306.0
|
||||
const EQUIPMENT_UI_SCALE := 0.8
|
||||
var _debug_scroll: ScrollContainer
|
||||
var _debug_actions: VBoxContainer
|
||||
var _debug_item_button: Button
|
||||
var _debug_item_status: Label
|
||||
var _captain_panel: PanelContainer
|
||||
var _cockpit: Control
|
||||
|
||||
@ -43,10 +40,6 @@ func _ready() -> void:
|
||||
# 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()
|
||||
var enemy_panel := Control.new()
|
||||
enemy_panel.name = "EnemyDrawer"
|
||||
enemy_panel.set_script(preload("res://scripts/ui/enemy_drawer.gd"))
|
||||
$HUDRoot.add_child(enemy_panel)
|
||||
_inventory_clip = Control.new()
|
||||
_inventory_clip.name = "InventoryDrawer"
|
||||
_inventory_clip.clip_contents = true
|
||||
@ -73,23 +66,6 @@ func _create_sidebar() -> void:
|
||||
_captain_panel.position = Vector2(12, 12)
|
||||
_captain_panel.size = Vector2(320, _captain_panel.get_combined_minimum_size().y)
|
||||
_captain_panel.resized.connect(_layout_debug)
|
||||
_debug_actions = VBoxContainer.new()
|
||||
_debug_actions.name = "DebugActions"
|
||||
_debug_actions.add_theme_constant_override("separation", 6)
|
||||
$HUDRoot.add_child(_debug_actions)
|
||||
_debug_item_button = Button.new()
|
||||
_debug_item_button.name = "GenerateItem"
|
||||
_debug_item_button.custom_minimum_size.y = 36
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(_debug_item_button, Color("a9ef83"))
|
||||
_debug_item_button.pressed.connect(_give_debug_item)
|
||||
_debug_actions.add_child(_debug_item_button)
|
||||
_debug_item_status = Label.new()
|
||||
_debug_item_status.add_theme_font_size_override("font_size", 10)
|
||||
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
|
||||
_debug_item_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_debug_item_status.hide()
|
||||
_debug_actions.add_child(_debug_item_status)
|
||||
_debug_actions.minimum_size_changed.connect(func() -> void: _layout_debug.call_deferred())
|
||||
_debug_scroll = ScrollContainer.new()
|
||||
_debug_scroll.name = "DebugScroll"
|
||||
_debug_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
@ -130,14 +106,13 @@ func _create_sidebar() -> void:
|
||||
_sidebar_toggle.name = "ShipToggle"
|
||||
_sidebar_toggle.text = "STATEK ▾" if _sidebar_open else "STATEK ◀"
|
||||
_sidebar_toggle.add_theme_font_size_override("font_size", 12)
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(_sidebar_toggle)
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(inventory_button, Color("b9a0ef"))
|
||||
_sidebar_toggle.focus_mode = Control.FOCUS_NONE
|
||||
$HUDRoot.add_child(_sidebar_toggle)
|
||||
_sidebar_toggle.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
||||
_sidebar_toggle.offset_left = -180
|
||||
_sidebar_toggle.offset_right = -12
|
||||
_sidebar_toggle.offset_top = 12
|
||||
_sidebar_toggle.offset_bottom = 48
|
||||
_sidebar_toggle.offset_bottom = 40
|
||||
_sidebar_toggle.pressed.connect(_toggle_sidebar)
|
||||
_cockpit = Control.new()
|
||||
_cockpit.name = "Cockpit"
|
||||
@ -152,12 +127,8 @@ func _layout_debug() -> void:
|
||||
return
|
||||
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
|
||||
debug_toggle.position = Vector2(12, top)
|
||||
_debug_actions.position = Vector2(18, top + 30)
|
||||
_debug_actions.size = Vector2(310, _debug_actions.get_combined_minimum_size().y)
|
||||
_debug_actions.visible = _debug_expanded
|
||||
var scroll_top := _debug_actions.position.y + _debug_actions.size.y + 8.0
|
||||
_debug_scroll.position = Vector2(18, scroll_top)
|
||||
_debug_scroll.size = Vector2(310, maxf(40, $HUDRoot.size.y - scroll_top - 12))
|
||||
_debug_scroll.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:
|
||||
@ -183,14 +154,10 @@ func _layout_sidebar() -> void:
|
||||
_sidebar.scale = Vector2.ONE * EQUIPMENT_UI_SCALE
|
||||
_sidebar.size = Vector2(maxf(SIDEBAR_WIDTH, _sidebar.get_combined_minimum_size().x), minf(_sidebar.get_node("Scroll/Contents").get_combined_minimum_size().y + 16.0, maxf(100.0, ($HUDRoot.size.y - 64.0) / EQUIPMENT_UI_SCALE)))
|
||||
_cockpit.scale = Vector2.ONE * 0.85
|
||||
_cockpit.size = Vector2(minf(640.0, ($HUDRoot.size.x - 24) / 0.85), 104)
|
||||
_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)
|
||||
if _ability_bar != null:
|
||||
var abilities := _ability_bar.get_parent() as Control
|
||||
abilities.offset_bottom = _cockpit.position.y - $HUDRoot.size.y - 14.0
|
||||
abilities.offset_top = abilities.offset_bottom - 44.0
|
||||
_layout_debug()
|
||||
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x * EQUIPMENT_UI_SCALE - 8 if _sidebar_open else $HUDRoot.size.x, 56)
|
||||
_sidebar.position = Vector2($HUDRoot.size.x - _sidebar.size.x * EQUIPMENT_UI_SCALE - 8 if _sidebar_open else $HUDRoot.size.x, 44)
|
||||
_sidebar.visible = _sidebar_open
|
||||
_inventory_clip.size = inventory_panel.size * EQUIPMENT_UI_SCALE
|
||||
_layout_inventory()
|
||||
@ -206,10 +173,6 @@ func _process(_delta: float) -> void:
|
||||
_update_ability_bar()
|
||||
if not _debug_expanded:
|
||||
return
|
||||
var inventory := player.get_node("ShipInventory") as ShipInventory
|
||||
_debug_item_button.text = "LOSUJ PRZEDMIOT · POZ. %d" % GameState.system_level
|
||||
_debug_item_button.disabled = inventory.get_cargo_used() >= ShipInventory.CARGO_SIZE
|
||||
_debug_item_button.tooltip_text = "Magazyn jest pełny — zwolnij miejsce." if _debug_item_button.disabled else "Losuje przedmiot i addony dla poziomu aktualnego układu."
|
||||
var game := get_parent()
|
||||
debug_info.text = """POZIOM UKŁADU: %d
|
||||
WROGOWIE: %d
|
||||
@ -233,25 +196,7 @@ func _toggle_debug() -> void:
|
||||
GameState.hud_panel_state["debug_expanded"] = _debug_expanded
|
||||
debug_info.visible = _debug_expanded
|
||||
_debug_scroll.visible = _debug_expanded
|
||||
_debug_actions.visible = _debug_expanded
|
||||
_update_debug_toggle()
|
||||
_layout_debug()
|
||||
|
||||
func _give_debug_item() -> bool:
|
||||
var inventory := player.get_node("ShipInventory") as ShipInventory
|
||||
_debug_item_status.show()
|
||||
if inventory.get_cargo_used() >= ShipInventory.CARGO_SIZE:
|
||||
_debug_item_status.text = "Magazyn pełny — zwolnij miejsce."
|
||||
_debug_item_status.add_theme_color_override("font_color", Color("ff8989"))
|
||||
_layout_debug.call_deferred()
|
||||
return false
|
||||
var item := preload("res://scripts/items/item_generator.gd").generate(GameState.system_level)
|
||||
if not inventory.add_item(item):
|
||||
return false
|
||||
_debug_item_status.text = "Dodano: %s · Poz. %d" % [item.definition.display_name, item.item_level]
|
||||
_debug_item_status.add_theme_color_override("font_color", Color("a9ef83"))
|
||||
_layout_debug.call_deferred()
|
||||
return true
|
||||
|
||||
func _update_debug_toggle() -> void:
|
||||
debug_toggle.text = "DEBUG [−]" if _debug_expanded else "DEBUG [+]"
|
||||
@ -312,8 +257,8 @@ func _create_ability_bar() -> void:
|
||||
panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM)
|
||||
panel.offset_left = -120.0
|
||||
panel.offset_right = 120.0
|
||||
panel.offset_top = -220.0
|
||||
panel.offset_bottom = -176.0
|
||||
panel.offset_top = -176.0
|
||||
panel.offset_bottom = -132.0
|
||||
panel.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
||||
_ability_bar = HBoxContainer.new()
|
||||
_ability_bar.name = "AbilityButtons"
|
||||
|
||||
@ -10,7 +10,7 @@ const WORLD_SIZE := SYSTEM_GENERATOR.WORLD_SIZE
|
||||
const SERVICE_APPROACH_DISTANCE := 180.0
|
||||
const WORMHOLE_PLANET_DISTANCE := 620.0
|
||||
const WORMHOLE_ENTRY_RADIUS := 48.0
|
||||
const BOSS_SPAWN_DISTANCE := 1800.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_TEXTURES: Array[Texture2D] = preload("res://scripts/items/alien_ship_catalog.gd").TEXTURES
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
extends Node
|
||||
|
||||
var remaining := 0.0
|
||||
var tick_damage := 0.0
|
||||
var credited_to_player := false
|
||||
var _tick_elapsed := 0.0
|
||||
var _base_color := Color.WHITE
|
||||
var _sprite: Sprite2D
|
||||
|
||||
static func apply(target: Node, damage_per_second: float, player_hit: bool) -> void:
|
||||
if not target.has_method("take_damage") or not target is CharacterBody2D:
|
||||
return
|
||||
var status := target.get_node_or_null("RadiationStatus")
|
||||
if status == null:
|
||||
status = Node.new()
|
||||
status.set_script(load("res://scripts/game/radiation_status.gd"))
|
||||
status.name = "RadiationStatus"
|
||||
target.add_child(status)
|
||||
status.remaining = 3.0
|
||||
status.tick_damage = maxf(status.tick_damage, damage_per_second)
|
||||
status.credited_to_player = player_hit
|
||||
|
||||
func _ready() -> void:
|
||||
_sprite = get_parent().get_node_or_null("Sprite2D")
|
||||
if _sprite != null:
|
||||
_base_color = _sprite.modulate
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var step := minf(delta, remaining)
|
||||
remaining = maxf(0.0, remaining - delta)
|
||||
var target := get_parent()
|
||||
if _sprite != null:
|
||||
_sprite.modulate = Color(0.3, 1.0, 0.35) if remaining > 0.0 else _base_color
|
||||
_tick_elapsed += step
|
||||
if _tick_elapsed >= 0.5 or (remaining <= 0.0 and _tick_elapsed > 0.0):
|
||||
step = _tick_elapsed
|
||||
_tick_elapsed = 0.0
|
||||
if credited_to_player and target.has_method("take_weapon_hit"):
|
||||
target.take_weapon_hit(tick_damage * step, false, DamageTypes.Type.RADIATION)
|
||||
else:
|
||||
target.take_damage(tick_damage * step, false, DamageTypes.Type.RADIATION)
|
||||
if remaining <= 0.0:
|
||||
tick_damage = 0.0
|
||||
@ -1 +0,0 @@
|
||||
uid://drtwspjwle1py
|
||||
@ -35,7 +35,6 @@ var shields := 100.0
|
||||
var energy := 100.0
|
||||
var energy_regeneration := 5.0
|
||||
var shield_regeneration := 0.0
|
||||
var absorption := Vector3.ZERO
|
||||
var damage_multiplier := 1.0
|
||||
var experience_multiplier := 1.0
|
||||
var credits_multiplier := 1.0
|
||||
@ -70,7 +69,6 @@ func _enter_tree() -> void:
|
||||
base_max_speed = float(chassis["speed"])
|
||||
|
||||
func apply_equipment_bonuses(bonuses: Dictionary) -> void:
|
||||
absorption = DamageTypes.capped(Vector3(float(bonuses.get("kinetic_absorption", 0.0)), float(bonuses.get("energy_absorption", 0.0)), float(bonuses.get("radiation_absorption", 0.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)
|
||||
scanner_range = base_scanner_range + float(bonuses.get("scanner_range", 0.0))
|
||||
@ -136,10 +134,10 @@ func _ensure_input_action(action_name: StringName, physical_key: Key) -> void:
|
||||
if not InputMap.action_has_event(action_name, event):
|
||||
InputMap.action_add_event(action_name, event)
|
||||
|
||||
func take_damage(amount: float, _critical: bool = false, damage_type: int = DamageTypes.Type.KINETIC) -> void:
|
||||
func take_damage(amount: float) -> void:
|
||||
if _is_destroyed or is_docked or amount <= 0.0:
|
||||
return
|
||||
var hit := COMBAT_ROLLS.incoming_hit(amount * (1.0 - absorption[damage_type] / 100.0), get_evasion_chance(), get_damage_reduction())
|
||||
var hit := COMBAT_ROLLS.incoming_hit(amount, get_evasion_chance(), get_damage_reduction())
|
||||
if hit["evaded"]:
|
||||
var flash := Node2D.new()
|
||||
flash.set_script(COMBAT_FLASH)
|
||||
|
||||
@ -2,7 +2,6 @@ extends RefCounted
|
||||
class_name WeaponAudio
|
||||
|
||||
const SOUND_PATHS := {
|
||||
ItemDefinition.WeaponKind.GAMMA: "res://assets/sounds/effects/plasma.mp3",
|
||||
ItemDefinition.WeaponKind.PLASMA: "res://assets/sounds/effects/plasma.mp3",
|
||||
ItemDefinition.WeaponKind.MACHINE_GUN: "res://assets/sounds/effects/machine_gun.mp3",
|
||||
ItemDefinition.WeaponKind.LASER: "res://assets/sounds/effects/laser.mp3",
|
||||
@ -12,7 +11,6 @@ const SOUND_PATHS := {
|
||||
static var _streams: Dictionary = {}
|
||||
|
||||
const BUS_NAMES := {
|
||||
ItemDefinition.WeaponKind.GAMMA: &"Plasma",
|
||||
ItemDefinition.WeaponKind.PLASMA: &"Plasma",
|
||||
ItemDefinition.WeaponKind.MACHINE_GUN: &"MachineGun",
|
||||
ItemDefinition.WeaponKind.LASER: &"Laser",
|
||||
|
||||
@ -205,8 +205,6 @@ func _muzzle_position() -> Vector2:
|
||||
func _consume_shot_resource(item: ItemInstance) -> bool:
|
||||
if item.definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||
return inventory.consume_ammunition()
|
||||
if item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
return inventory.consume_irradiated_ammunition()
|
||||
return _consume_energy(item.get_energy_cost())
|
||||
|
||||
func _consume_energy(amount: float) -> bool:
|
||||
@ -218,7 +216,7 @@ func _consume_energy(amount: float) -> bool:
|
||||
|
||||
func _apply_damage(target: Variant, damage: float, critical: bool = false) -> void:
|
||||
if target is Node and target.has_method("take_weapon_hit"):
|
||||
target.call("take_weapon_hit", damage, critical, DamageTypes.Type.ENERGY)
|
||||
target.call("take_weapon_hit", damage, critical)
|
||||
elif target is Node and target.has_method("take_damage"):
|
||||
target.call("take_damage", damage)
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ const IMPACT_EFFECT_SCENE := preload("res://scenes/game/impact_effect.tscn")
|
||||
const PLASMA_TEXTURE := preload("res://assets/other/bullet.png")
|
||||
const PLASMA_VISUAL_WIDTH := 24.0
|
||||
|
||||
var enemy_shot := false
|
||||
var direction := Vector2.UP
|
||||
var projectile_speed := 600.0
|
||||
var damage := 1.0
|
||||
@ -125,9 +124,6 @@ func _physics_process(delta: float) -> void:
|
||||
queue_free()
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
_engine_time += delta
|
||||
queue_redraw()
|
||||
if weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||
_engine_time += delta
|
||||
_smoke_emission_timer += delta
|
||||
@ -161,8 +157,6 @@ func _update_smoke_puffs(delta: float) -> void:
|
||||
func _find_enemy_in_acquisition_range() -> Node2D:
|
||||
var nearest_enemy: Node2D
|
||||
var nearest_distance_squared := target_acquisition_range * target_acquisition_range
|
||||
if enemy_shot:
|
||||
return null
|
||||
for candidate in get_tree().get_nodes_in_group("enemies"):
|
||||
if not candidate is Node2D or candidate.is_queued_for_deletion():
|
||||
continue
|
||||
@ -176,15 +170,6 @@ func _draw() -> void:
|
||||
if weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||
_draw_missile_smoke()
|
||||
match weapon_kind:
|
||||
ItemDefinition.WeaponKind.GAMMA:
|
||||
var radius := 9.0 + sin(_engine_time * 9.0) * 2.0
|
||||
draw_circle(Vector2.ZERO, radius * 1.8, Color(0.3, 1.0, 0.1, 0.15))
|
||||
draw_circle(Vector2.ZERO, radius, Color(0.35, 0.95, 0.15, 0.8))
|
||||
draw_circle(Vector2.ZERO, radius * 0.5, Color(0.86, 1.0, 0.6))
|
||||
for index in 8:
|
||||
var angle := _engine_time * 5.0 + index * TAU / 8.0
|
||||
var orbit := Vector2(cos(angle), sin(angle) * 0.65) * (radius + 6.0)
|
||||
draw_circle(orbit, 2.0, Color(0.7, 1.0, 0.4))
|
||||
ItemDefinition.WeaponKind.PLASMA:
|
||||
var texture_size := PLASMA_TEXTURE.get_size() * (PLASMA_VISUAL_WIDTH / PLASMA_TEXTURE.get_width())
|
||||
# The source image points left; projectiles travel along their local +X.
|
||||
@ -264,9 +249,6 @@ func _spawn_impact_effect(is_explosion: bool) -> void:
|
||||
effect.global_position = global_position
|
||||
get_parent().add_child(effect)
|
||||
var effect_color := Color(1.0, 0.48, 0.22) if is_explosion else Color(1.0, 0.78, 0.38)
|
||||
if weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
effect_color = Color(0.4, 1.0, 0.15)
|
||||
is_explosion = true
|
||||
effect.call("configure", is_explosion, effect_color)
|
||||
|
||||
func _explode_at_target(impact_target: Node) -> void:
|
||||
@ -276,7 +258,7 @@ func _explode_at_target(impact_target: Node) -> void:
|
||||
var query := PhysicsShapeQueryParameters2D.new()
|
||||
query.shape = explosion_shape
|
||||
query.transform = Transform2D(0.0, global_position)
|
||||
query.collision_mask = 2 if enemy_shot else 4
|
||||
query.collision_mask = 4 # Enemy physics layer 3.
|
||||
for result in get_world_2d().direct_space_state.intersect_shape(query, 32):
|
||||
_apply_damage_once(result.get("collider"))
|
||||
|
||||
@ -288,11 +270,6 @@ func _apply_damage_once(target: Variant) -> void:
|
||||
return
|
||||
_already_hit[instance_id] = true
|
||||
if target.has_method("take_weapon_hit"):
|
||||
target.call("take_weapon_hit", damage, is_critical, DamageTypes.for_weapon(weapon_kind))
|
||||
target.call("take_weapon_hit", damage, is_critical)
|
||||
elif target.has_method("take_damage"):
|
||||
if target is CharacterBody2D:
|
||||
target.call("take_damage", damage, is_critical, DamageTypes.for_weapon(weapon_kind))
|
||||
else:
|
||||
target.call("take_damage", damage)
|
||||
if weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
preload("res://scripts/game/radiation_status.gd").apply(target, damage * 0.25, not enemy_shot)
|
||||
target.call("take_damage", damage)
|
||||
|
||||
@ -2,10 +2,7 @@ extends Resource
|
||||
class_name ItemDefinition
|
||||
|
||||
enum Category { WEAPON, SHIELD, ARMOR, REACTOR, ENGINE, ACTIVE_EXTENSION, COMPUTER }
|
||||
enum WeaponKind { PLASMA, MACHINE_GUN, LASER, MISSILE, GAMMA }
|
||||
|
||||
func get_damage_type() -> int:
|
||||
return DamageTypes.for_weapon(weapon_kind)
|
||||
enum WeaponKind { PLASMA, MACHINE_GUN, LASER, MISSILE }
|
||||
|
||||
@export var item_id: String = ""
|
||||
@export var display_name: String = ""
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
extends RefCounted
|
||||
|
||||
const DEFINITIONS := [
|
||||
preload("res://resources/items/gamma_cannon.tres"),
|
||||
preload("res://resources/items/plasma_cannon.tres"),
|
||||
preload("res://resources/items/beam_laser.tres"),
|
||||
preload("res://resources/items/machine_gun.tres"),
|
||||
|
||||
@ -55,7 +55,7 @@ func roll_damage() -> float:
|
||||
func get_energy_cost() -> float:
|
||||
if definition == null or definition.category != ItemDefinition.Category.WEAPON:
|
||||
return 0.0
|
||||
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE, ItemDefinition.WeaponKind.GAMMA]:
|
||||
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE]:
|
||||
return 0.0
|
||||
# Compare this weapon with its starter damage. Captain/global gear buffs are free.
|
||||
var base_lower := roundf((definition.damage_lower_roll_min + definition.damage_lower_roll_max) * 0.5)
|
||||
@ -88,8 +88,7 @@ func get_addon_count() -> int:
|
||||
return count
|
||||
|
||||
func get_background_color() -> Color:
|
||||
# No addons and one addon are black; the strongest tier is burgundy.
|
||||
return [Color("080b10"), Color("080b10"), Color("603e28"), Color("285b91"), Color("8050b8"), Color("70243c")][clampi(get_addon_count(), 0, 5)]
|
||||
return [Color("101925"), Color("414b58"), Color("65432d"), Color("244c79"), Color("796025")][mini(get_addon_count(), 4)]
|
||||
|
||||
func get_type_color() -> Color:
|
||||
if definition == null:
|
||||
@ -113,12 +112,9 @@ func get_tooltip_text() -> String:
|
||||
if definition.energy_regeneration_bonus > 0.0:
|
||||
lines.append("Regeneracja generatora: +%.1f /s" % ((energy_regeneration_override if energy_regeneration_override >= 0.0 else definition.energy_regeneration_bonus) * ENERGY_REGENERATION_BONUS_MULTIPLIER))
|
||||
if definition.category == ItemDefinition.Category.WEAPON:
|
||||
lines.append("Typ obrażeń: %s" % DamageTypes.NAMES[definition.get_damage_type()])
|
||||
lines.append("Każdy strzał / impuls losuje obrażenia z tego zakresu.")
|
||||
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||
lines.append("Zasięg: %.0f px • Amunicja: 1 / strzał" % definition.weapon_range)
|
||||
elif definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
lines.append("Zasięg: %.0f px • Napromieniowana amunicja: 1 / strzał" % definition.weapon_range)
|
||||
elif definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||
lines.append("Amunicja: 1 rakieta / strzał • Cooldown bazowy: 5 s • Bez kosztu energii")
|
||||
else:
|
||||
@ -133,4 +129,4 @@ func get_tooltip_text() -> String:
|
||||
return "\n".join(lines)
|
||||
|
||||
static func stat_name(key: String) -> String:
|
||||
return str({"kinetic_absorption": "Absorpcja kinetyczna", "energy_absorption": "Absorpcja energetyczna", "radiation_absorption": "Absorpcja radiacyjna", "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))
|
||||
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))
|
||||
|
||||
@ -20,8 +20,6 @@ const AMMUNITION_CRAFT_PARTS_COST := 50.0
|
||||
const AMMUNITION_BUY_AMOUNT := 100
|
||||
const AMMUNITION_BUY_BASE_COST := 20
|
||||
|
||||
var irradiated_ammunition := 0
|
||||
|
||||
var ammunition: int = STARTING_AMMUNITION
|
||||
var missile_ammunition: int = STARTING_MISSILE_AMMUNITION
|
||||
|
||||
@ -47,7 +45,6 @@ func _ready() -> void:
|
||||
_restore_modules(GameState.restart_inventory)
|
||||
ammunition = int(GameState.restart_inventory.get("ammunition", STARTING_AMMUNITION))
|
||||
missile_ammunition = int(GameState.restart_inventory.get("missile_ammunition", STARTING_MISSILE_AMMUNITION))
|
||||
irradiated_ammunition = int(GameState.restart_inventory.get("irradiated_ammunition", 0))
|
||||
GameState.restart_inventory.clear()
|
||||
_remove_extension_addons()
|
||||
_recalculate_ship_stats()
|
||||
@ -67,7 +64,6 @@ func preserve_for_restart() -> void:
|
||||
"weapon": weapon_slots.duplicate(),
|
||||
"module": module_slots.duplicate(),
|
||||
"extension": extension_slots.duplicate(),
|
||||
"irradiated_ammunition": irradiated_ammunition,
|
||||
"ammunition": ammunition,
|
||||
"missile_ammunition": missile_ammunition,
|
||||
}
|
||||
@ -235,7 +231,7 @@ func _recalculate_ship_stats() -> void:
|
||||
for item in weapon_slots + module_slots:
|
||||
if item == null or item.definition == null:
|
||||
continue
|
||||
for stat_key in ["kinetic_absorption", "energy_absorption", "radiation_absorption", "shield_on_damage_percent", "scanner_range", "max_hull", "max_shields", "max_energy", "max_speed", "energy_regeneration", "shield_regeneration", "hull_percent", "shield_percent", "damage_percent", "speed_percent", "experience_percent", "credits_percent", "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)
|
||||
ship.call("apply_equipment_bonuses", bonuses)
|
||||
|
||||
@ -292,7 +288,7 @@ func _comparison_bonuses(incoming: ItemInstance = null, outgoing: ItemInstance =
|
||||
return bonuses
|
||||
|
||||
func _add_comparison_bonuses(bonuses: Dictionary, item: ItemInstance) -> void:
|
||||
for key in ["kinetic_absorption", "energy_absorption", "radiation_absorption", "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"]:
|
||||
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:
|
||||
@ -303,12 +299,9 @@ func _comparison_stats(bonuses: Dictionary) -> Dictionary:
|
||||
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]}
|
||||
# These stats are bonuses in their own right, not rewards or hit scenarios.
|
||||
for data in [["kinetic_absorption", "Absorpcja kinetyczna"], ["energy_absorption", "Absorpcja energetyczna"], ["radiation_absorption", "Absorpcja radiacyjna"], ["damage_percent", "Obrażenia broni"], ["critical_damage_percent", "Obrażenia krytyczne"], ["critical_chance_percent", "Szansa na krytyk"], ["shield_on_damage_percent", "Odzysk tarcz z obrażeń"], ["experience_percent", "Doświadczenie"], ["credits_percent", "Kredyty"]]:
|
||||
for data in [["damage_percent", "Obrażenia broni"], ["critical_damage_percent", "Obrażenia krytyczne"], ["critical_chance_percent", "Szansa na krytyk"], ["shield_on_damage_percent", "Odzysk tarcz z obrażeń"], ["experience_percent", "Doświadczenie"], ["credits_percent", "Kredyty"]]:
|
||||
stats[data[0]] = {"value": float(bonuses.get(data[0], 0.0)), "name": data[1], "unit": "%"}
|
||||
stats["missile_cooldown_reduction"] = {"value": float(bonuses.get("missile_cooldown_reduction", 0.0)), "name": "Skrócenie cooldownu rakiet", "unit": "s"}
|
||||
var absorption_values := DamageTypes.capped(Vector3(float(bonuses.get("kinetic_absorption", 0.0)), float(bonuses.get("energy_absorption", 0.0)), float(bonuses.get("radiation_absorption", 0.0))))
|
||||
for index in 3:
|
||||
stats[DamageTypes.KEYS[index]]["value"] = absorption_values[index]
|
||||
return stats
|
||||
|
||||
func get_weapon_comparison(item: ItemInstance, slot_index: int) -> Dictionary:
|
||||
@ -341,45 +334,3 @@ func _weapon_dps(item: ItemInstance, bonuses: Dictionary) -> float:
|
||||
if item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||
interval = maxf(1.0, 5.0 - float(bonuses.get("missile_cooldown_reduction", 0.0)))
|
||||
return item.get_stat_total("damage") * damage_factor * (1.0 + chance * (critical_factor - 1.0)) / maxf(0.001, interval)
|
||||
|
||||
func consume_irradiated_ammunition() -> bool:
|
||||
if irradiated_ammunition <= 0:
|
||||
return false
|
||||
irradiated_ammunition -= 1
|
||||
ammunition_changed.emit()
|
||||
return true
|
||||
|
||||
func can_craft_irradiated_ammunition() -> bool:
|
||||
return int(GameState.captain.minerals.get("uranium", 0)) >= 1 and GameState.captain.parts >= 10.0
|
||||
|
||||
func craft_irradiated_ammunition() -> bool:
|
||||
if not can_craft_irradiated_ammunition():
|
||||
return false
|
||||
GameState.captain.minerals["uranium"] -= 1
|
||||
GameState.captain.parts -= 10.0
|
||||
irradiated_ammunition += 10
|
||||
GameState.captain.emit_changed()
|
||||
ammunition_changed.emit()
|
||||
return true
|
||||
|
||||
func can_buy_irradiated_ammunition() -> bool:
|
||||
return GameState.captain.credits >= 15 * maxi(1, GameState.system_level)
|
||||
|
||||
func buy_irradiated_ammunition() -> bool:
|
||||
if not can_buy_irradiated_ammunition():
|
||||
return false
|
||||
GameState.captain.credits -= 15 * maxi(1, GameState.system_level)
|
||||
irradiated_ammunition += 10
|
||||
GameState.captain.emit_changed()
|
||||
ammunition_changed.emit()
|
||||
return true
|
||||
|
||||
func get_total_dps() -> float:
|
||||
var total := 0.0
|
||||
var bonuses := _comparison_bonuses()
|
||||
for item in weapon_slots:
|
||||
var value := _weapon_dps(item, bonuses)
|
||||
if item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||
value *= 1.0 + 0.25 * minf(3.0, item.definition.fire_interval)
|
||||
total += value
|
||||
return total
|
||||
|
||||
@ -22,7 +22,7 @@ var _asteroid_spin := 0.0
|
||||
func _ready() -> void:
|
||||
add_to_group("exploration_pois")
|
||||
_rng.seed = reward_seed
|
||||
_mineral = ["iron", "aluminium", "titanium", "uranium"][_rng.randi_range(0, 3)]
|
||||
_mineral = ["iron", "aluminium", "titanium"][_rng.randi_range(0, 2)]
|
||||
hull = 20.0 * reward_scale()
|
||||
collision_layer = 4 if kind == "asteroid" else 0
|
||||
collision_mask = 0
|
||||
@ -79,7 +79,7 @@ func _update_label(near: bool) -> void:
|
||||
if kind == "ruin":
|
||||
_label.text = "?"
|
||||
elif kind == "asteroid":
|
||||
_label.text = "Asteroida · %s\nHP: %.0f" % [{"iron": "Żelazo", "aluminium": "Aluminium", "titanium": "Tytan", "uranium": "Uran"}[_mineral], hull]
|
||||
_label.text = "Asteroida · %s\nHP: %.0f" % [{"iron": "Żelazo", "aluminium": "Aluminium", "titanium": "Tytan"}[_mineral], hull]
|
||||
else:
|
||||
_label.text = ("Wrak statku" if kind == "wreck" else "Antyczne znalezisko") + ("\n[E] Przeszukaj" if near else "\nPodleć, aby przeszukać")
|
||||
|
||||
@ -91,7 +91,7 @@ func _physics_process(_delta: float) -> void:
|
||||
if near and (kind == "ruin" or (kind == "wreck" and Input.is_physical_key_pressed(KEY_E))):
|
||||
claim()
|
||||
|
||||
func take_weapon_hit(amount: float, _critical: bool = false, _damage_type: int = 0) -> void:
|
||||
func take_weapon_hit(amount: float, _critical: bool = false) -> void:
|
||||
take_damage(amount)
|
||||
|
||||
func take_damage(amount: float) -> void:
|
||||
@ -114,7 +114,7 @@ func claim() -> bool:
|
||||
if kind == "asteroid":
|
||||
var amount := maxi(1, roundi(_rng.randi_range(1, 3) * scale))
|
||||
GameState.captain.minerals[_mineral] = int(GameState.captain.minerals.get(_mineral, 0)) + amount
|
||||
summary = "+%d %s" % [amount, {"iron": "żelaza", "aluminium": "aluminium", "titanium": "tytanu", "uranium": "uranu"}[_mineral]]
|
||||
summary = "+%d %s" % [amount, {"iron": "żelaza", "aluminium": "aluminium", "titanium": "tytanu"}[_mineral]]
|
||||
elif kind == "ruin":
|
||||
var xp := roundi(_rng.randi_range(10, 20) * scale)
|
||||
GameState.captain.add_rewards(xp, 0)
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
extends Control
|
||||
|
||||
var _panel: PanelContainer
|
||||
var _label: Label
|
||||
var _toggle: Button
|
||||
var _open := false
|
||||
var _tween: Tween
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||
_panel = PanelContainer.new()
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color("0b1520f5")
|
||||
style.border_color = Color("a54e61")
|
||||
style.set_border_width_all(1)
|
||||
style.set_content_margin_all(12)
|
||||
_panel.add_theme_stylebox_override("panel", style)
|
||||
add_child(_panel)
|
||||
_label = Label.new()
|
||||
_label.add_theme_font_size_override("font_size", 12)
|
||||
_panel.add_child(_label)
|
||||
_toggle = Button.new()
|
||||
_toggle.text = "WRÓG ▾"
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(_toggle, Color("ff9aae"))
|
||||
add_child(_toggle)
|
||||
_toggle.pressed.connect(_toggle_drawer)
|
||||
_open = bool(GameState.hud_panel_state.get("enemy_open", false))
|
||||
get_viewport().size_changed.connect(_layout)
|
||||
_layout()
|
||||
|
||||
func _layout() -> void:
|
||||
position.x = (get_viewport_rect().size.x - 390.0) * 0.5
|
||||
_panel.size = Vector2(390, 150)
|
||||
_panel.position.y = 56.0 if _open else -160.0
|
||||
_toggle.position = Vector2(130, 12)
|
||||
_toggle.size = Vector2(130, 36)
|
||||
|
||||
func _toggle_drawer() -> void:
|
||||
_open = not _open
|
||||
GameState.hud_panel_state["enemy_open"] = _open
|
||||
_toggle.text = "WRÓG ▴" if _open else "WRÓG ▾"
|
||||
if _tween != null:
|
||||
_tween.kill()
|
||||
_tween = create_tween()
|
||||
_tween.tween_property(_panel, "position:y", 56.0 if _open else -160.0, 0.25).set_trans(Tween.TRANS_CUBIC)
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var enemy: Node = null
|
||||
for candidate in get_tree().get_nodes_in_group("enemies"):
|
||||
if not candidate.is_queued_for_deletion() and (enemy == null or int(candidate.loot_tier) < int(enemy.loot_tier)):
|
||||
enemy = candidate
|
||||
var profile := DamageTypes.enemy_profile(GameState.system_level, GameState.system_seed)
|
||||
var kind := int(profile["kind"])
|
||||
var names := ["Działko plazmowe", "Działko maszynowe", "Laser", "Rakiety", "Działko gamma"]
|
||||
_label.text = "WRÓG · UKŁAD %d\n%s · %s\n%s" % [GameState.system_level, names[kind], DamageTypes.NAMES[DamageTypes.for_weapon(kind)], DamageTypes.describe(profile["absorption"])]
|
||||
if enemy != null:
|
||||
_label.text += "\nDPS: %.1f (%s)\nTarcze: %.0f / %.0f · bez regeneracji" % [enemy.get_weapon_dps(), ["zwykły", "elita", "boss"][enemy.loot_tier], enemy.shields, enemy.max_shields]
|
||||
else:
|
||||
_label.text += "\nUkład oczyszczony"
|
||||
@ -1 +0,0 @@
|
||||
uid://d0ejbqbvdb2kq
|
||||
@ -59,7 +59,7 @@ func _ready() -> void:
|
||||
var binding := Label.new()
|
||||
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
binding.text = (["LPM", "PPM", "ŚPM"][slot_index]) if slot_kind == "weapon" else (str(slot_index + 1) if slot_kind == "extension" else ShipInventory.MODULE_NAMES[slot_index])
|
||||
binding.position = Vector2(2, -24)
|
||||
binding.position = Vector2(2, -14)
|
||||
binding.add_theme_font_size_override("font_size", 9)
|
||||
binding.add_theme_color_override("font_color", Color("a0b2c4"))
|
||||
# Use a plain overlay to keep the binding outside the slot's content layout.
|
||||
@ -134,108 +134,42 @@ func _delete_item() -> void:
|
||||
|
||||
func _make_custom_tooltip(for_text: String) -> Object:
|
||||
var panel := PanelContainer.new()
|
||||
panel.set_script(preload("res://scripts/ui/item_tooltip_frame.gd"))
|
||||
var background := StyleBoxFlat.new()
|
||||
background.bg_color = Color("101925")
|
||||
background.border_color = Color("52677e")
|
||||
background.set_border_width_all(1)
|
||||
background.border_width_top = 2
|
||||
background.set_content_margin_all(12)
|
||||
background.set_corner_radius_all(3)
|
||||
background.shadow_size = 0
|
||||
panel.add_theme_stylebox_override("panel", background)
|
||||
var label := RichTextLabel.new()
|
||||
label.fit_content = true
|
||||
label.scroll_active = false
|
||||
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
label.custom_minimum_size.x = 290
|
||||
label.size.x = 290
|
||||
label.custom_minimum_size.x = 330
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
label.add_theme_font_size_override("normal_font_size", 11)
|
||||
label.add_theme_constant_override("line_separation", -2)
|
||||
label.add_theme_color_override("default_color", Color("c4d2df"))
|
||||
label.add_theme_font_size_override("normal_font_size", 13)
|
||||
var item := _inventory.get_item(slot_kind, slot_index)
|
||||
if item:
|
||||
# Dark neutral body with an accent tied to the equipment category.
|
||||
background.bg_color = Color("0c1520").lerp(item.get_background_color().darkened(0.8), 0.25)
|
||||
background.bg_color = item.get_background_color()
|
||||
background.border_color = item.get_type_color()
|
||||
panel.set("accent", item.get_type_color())
|
||||
var columns := HBoxContainer.new()
|
||||
columns.add_theme_constant_override("separation", 12)
|
||||
panel.add_child(columns)
|
||||
var details := VBoxContainer.new()
|
||||
details.custom_minimum_size.x = 290
|
||||
details.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
details.add_theme_constant_override("separation", 8)
|
||||
columns.add_child(details)
|
||||
var lines := for_text.split("\n")
|
||||
if item != null:
|
||||
var header_frame := PanelContainer.new()
|
||||
var header_style := StyleBoxFlat.new()
|
||||
header_style.bg_color = item.get_type_color().darkened(0.8)
|
||||
header_style.border_color = item.get_type_color().darkened(0.35)
|
||||
header_style.border_width_left = 3
|
||||
header_style.set_content_margin_all(8)
|
||||
header_frame.add_theme_stylebox_override("panel", header_style)
|
||||
details.add_child(header_frame)
|
||||
var header := HBoxContainer.new()
|
||||
header.add_theme_constant_override("separation", 10)
|
||||
header_frame.add_child(header)
|
||||
if item.definition.icon != null:
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = item.definition.icon
|
||||
icon.custom_minimum_size = Vector2(54, 54)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
header.add_child(icon)
|
||||
var heading := VBoxContainer.new()
|
||||
heading.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
heading.add_theme_constant_override("separation", 2)
|
||||
header.add_child(heading)
|
||||
var title := _comparison_label(item.definition.display_name, 0, Color("f1f4f8"))
|
||||
title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
title.add_theme_font_size_override("font_size", 13)
|
||||
heading.add_child(title)
|
||||
heading.add_child(_comparison_label("%s · POZ. %d" % [item.get_rarity_name(), item.item_level], 0, item.get_type_color().lightened(0.25)))
|
||||
heading.add_child(_comparison_label("%s · ADDONY: %d/5" % [_category_name(item.definition.category), item.get_addon_count()], 0, Color("8ba2b7")))
|
||||
lines = lines.slice(2)
|
||||
while not lines.is_empty() and lines[0].is_empty():
|
||||
lines.remove_at(0)
|
||||
details.add_child(label)
|
||||
for line in lines:
|
||||
if line == "CECHA GŁÓWNA" or line.contains("ADDONY (aktywne"):
|
||||
label.push_font_size(10)
|
||||
label.push_color(Color("91dbea"))
|
||||
label.add_text("PARAMETRY\n" if line == "CECHA GŁÓWNA" else "ADDONY · PO ZAMONTOWANIU\n")
|
||||
label.pop()
|
||||
label.pop()
|
||||
continue
|
||||
label.add_theme_color_override("default_color", Color("f1f4f8"))
|
||||
for line in for_text.split("\n"):
|
||||
var quality := 0
|
||||
var is_addon := false
|
||||
if item:
|
||||
for modifier in item.additional_modifiers:
|
||||
if modifier != null and line == modifier.get_display_text():
|
||||
is_addon = true
|
||||
quality = modifier.get_roll_quality(item.item_level)
|
||||
break
|
||||
var color := Color("ffd166") if quality == 2 else (Color("79e6a0") if quality == 1 else Color("c4d2df"))
|
||||
if line.begins_with("Obrażenia:"):
|
||||
label.push_font_size(13)
|
||||
color = Color("ffd166")
|
||||
if line.begins_with("Typ obrażeń:"):
|
||||
color = [Color("efb568"), Color("91dbea"), Color("a9ef83")][item.definition.get_damage_type()] if item != null else Color("e6f2fc")
|
||||
if line.begins_with("Każdy strzał"):
|
||||
color = Color("8298ad")
|
||||
label.push_color(color)
|
||||
label.add_text(("★ " if quality == 2 else ("• " if is_addon else "")) + line + "\n")
|
||||
label.pop()
|
||||
if line.begins_with("Obrażenia:"):
|
||||
if quality > 0:
|
||||
label.push_color(Color("ffd166") if quality == 2 else Color("79e6a0"))
|
||||
label.add_text(("★ " if quality == 2 else "") + line + "\n")
|
||||
if quality > 0:
|
||||
label.pop()
|
||||
var columns := HBoxContainer.new()
|
||||
columns.add_theme_constant_override("separation", 16)
|
||||
panel.add_child(columns)
|
||||
columns.add_child(label)
|
||||
if slot_kind == "cargo" and item != null:
|
||||
_add_comparison_column(columns, item)
|
||||
# Wrapped text can become shorter after the first layout pass.
|
||||
panel.minimum_size_changed.connect(func() -> void: panel.reset_size.call_deferred())
|
||||
panel.reset_size.call_deferred()
|
||||
return panel
|
||||
|
||||
func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||
@ -251,18 +185,13 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||
comparison.fit_content = true
|
||||
comparison.scroll_active = false
|
||||
comparison.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
comparison.custom_minimum_size.x = 270
|
||||
comparison.size.x = 270
|
||||
comparison.custom_minimum_size.x = 290
|
||||
comparison.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
comparison.add_theme_font_size_override("normal_font_size", 11)
|
||||
comparison.add_theme_constant_override("line_separation", -2)
|
||||
comparison.add_theme_color_override("default_color", Color("c4d2df"))
|
||||
comparison.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
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.push_color(Color("91dbea"))
|
||||
comparison.add_text("ZMIANY PO ZAŁOŻENIU\n")
|
||||
comparison.pop()
|
||||
comparison.add_text("Slot: %s\n" % ShipInventory.MODULE_NAMES[module_index])
|
||||
comparison.add_text("Obecnie: %s\n\n" % ("%s • Poz. %d" % [equipped.definition.display_name, equipped.item_level] if equipped != null else "pusty"))
|
||||
comparison.add_text("Zmiana statystyk statku:\n")
|
||||
@ -274,17 +203,13 @@ func _add_comparison_column(columns: HBoxContainer, item: ItemInstance) -> void:
|
||||
var name: String = row["name"]
|
||||
comparison.add_text("%s: %+.2f %s\n" % [name, row["delta"], row["unit"]])
|
||||
comparison.pop()
|
||||
comparison.push_color(Color("8298ad"))
|
||||
comparison.push_font_size(10)
|
||||
comparison.add_text("\nUwzględnia utratę bonusów zdejmowanego przedmiotu.")
|
||||
comparison.pop()
|
||||
comparison.pop()
|
||||
|
||||
func _comparison_label(text_value: String, width: float, color: Color = Color("f1f4f8")) -> Label:
|
||||
var label := Label.new()
|
||||
label.text = text_value
|
||||
label.custom_minimum_size.x = width
|
||||
label.add_theme_font_size_override("font_size", 10)
|
||||
label.add_theme_font_size_override("font_size", 11)
|
||||
label.add_theme_color_override("font_color", color)
|
||||
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
return label
|
||||
|
||||
@ -32,34 +32,32 @@ func _draw() -> void:
|
||||
closed.append(outline[0])
|
||||
draw_polyline(closed, Color("376779"), 1.5, true)
|
||||
draw_line(Vector2(28, 2), Vector2(size.x - 28, 2), CYAN, 2, true)
|
||||
# Put weapon cards beside the counters rather than stacking three rows.
|
||||
_text("DPS: %.1f" % _inventory.get_total_dps(), Vector2(20, 81), 172, 12, CYAN)
|
||||
_text(DamageTypes.describe(player.get("absorption")), Vector2(205, 81), size.x - 225, 11, Color("a9d69a"))
|
||||
var cell := (size.x - 238) / 3.0
|
||||
var 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 := 218.0 + index * cell
|
||||
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"))
|
||||
if index == 1:
|
||||
_text("ZWYKŁE %02d" % _inventory.ammunition, Vector2(x, 35), cell, 11, CYAN)
|
||||
_text("GAMMA %02d" % _inventory.irradiated_ammunition, Vector2(x, 49), cell, 11, Color("a9ef83"))
|
||||
else:
|
||||
_text(str(values[index]).pad_zeros(2), Vector2(x, 45), cell, 21, color)
|
||||
_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(20 + index * 60, 12, 52, 52)
|
||||
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, 12), card.size.x, 9, CYAN)
|
||||
_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(9, 16), Vector2(34, 34)), false)
|
||||
draw_texture_rect(item.definition.icon, Rect2(card.position + Vector2(11, 18), Vector2(42, 42)), false)
|
||||
else:
|
||||
_text("—", card.position + Vector2(0, 36), card.size.x, 14, Color("637d90"))
|
||||
_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()
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
extends RefCounted
|
||||
|
||||
static func apply(button: Button, accent: Color = Color("91dbea")) -> void:
|
||||
button.focus_mode = Control.FOCUS_NONE
|
||||
button.add_theme_font_size_override("font_size", 12)
|
||||
button.add_theme_color_override("font_color", accent.lightened(0.25))
|
||||
button.add_theme_color_override("font_hover_color", Color.WHITE)
|
||||
button.add_theme_color_override("font_pressed_color", Color.WHITE)
|
||||
button.add_theme_color_override("font_disabled_color", Color("566b7d"))
|
||||
button.add_theme_stylebox_override("normal", _style(Color("10212e"), accent.darkened(0.45)))
|
||||
button.add_theme_stylebox_override("hover", _style(Color("193446"), accent))
|
||||
button.add_theme_stylebox_override("pressed", _style(accent.darkened(0.72), accent.lightened(0.15)))
|
||||
button.add_theme_stylebox_override("disabled", _style(Color("101820"), Color("2c3b46")))
|
||||
button.add_theme_constant_override("outline_size", 0)
|
||||
|
||||
static func _style(background: Color, border: Color) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = background
|
||||
style.border_color = border
|
||||
style.set_border_width_all(1)
|
||||
style.border_width_left = 3
|
||||
style.set_corner_radius_all(7)
|
||||
style.content_margin_left = 14
|
||||
style.content_margin_right = 14
|
||||
style.content_margin_top = 6
|
||||
style.content_margin_bottom = 6
|
||||
style.shadow_color = Color(0, 0, 0, 0.24)
|
||||
style.shadow_size = 3
|
||||
style.shadow_offset = Vector2(0, 2)
|
||||
return style
|
||||
@ -1 +0,0 @@
|
||||
uid://c8mg5jsryv3ig
|
||||
@ -1,71 +0,0 @@
|
||||
extends PanelContainer
|
||||
|
||||
var resource_name := ""
|
||||
var description := ""
|
||||
var accent := Color("91dbea")
|
||||
var icon_texture: Texture2D
|
||||
var _count: Label
|
||||
|
||||
func _ready() -> void:
|
||||
custom_minimum_size = Vector2(86, 44)
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
var style := _style(false)
|
||||
add_theme_stylebox_override("panel", style)
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 5)
|
||||
add_child(row)
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = icon_texture
|
||||
icon.custom_minimum_size = Vector2(32, 32)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
row.add_child(icon)
|
||||
_count = Label.new()
|
||||
_count.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_count.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
_count.add_theme_font_size_override("font_size", 11)
|
||||
_count.add_theme_color_override("font_color", accent.lightened(0.2))
|
||||
_count.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
row.add_child(_count)
|
||||
row.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
mouse_entered.connect(func() -> void: add_theme_stylebox_override("panel", _style(true)))
|
||||
mouse_exited.connect(func() -> void: add_theme_stylebox_override("panel", _style(false)))
|
||||
set_amount(0)
|
||||
|
||||
func _style(hovered: bool) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color("172737") if hovered else Color("0c1723")
|
||||
style.border_color = accent if hovered else accent.darkened(0.65)
|
||||
style.set_border_width_all(1)
|
||||
style.set_corner_radius_all(4)
|
||||
style.content_margin_left = 6
|
||||
style.content_margin_right = 6
|
||||
style.content_margin_top = 5
|
||||
style.content_margin_bottom = 5
|
||||
return style
|
||||
|
||||
func set_amount(amount: float) -> void:
|
||||
if _count == null:
|
||||
return
|
||||
_count.text = str(roundi(amount)) if is_equal_approx(amount, roundf(amount)) else "%.1f" % amount
|
||||
tooltip_text = "%s\n%s\nZapas: %s" % [resource_name, description, _count.text]
|
||||
|
||||
func _make_custom_tooltip(_text: String) -> Object:
|
||||
var panel := PanelContainer.new()
|
||||
panel.add_theme_stylebox_override("panel", _style(true))
|
||||
var contents := VBoxContainer.new()
|
||||
contents.add_theme_constant_override("separation", 4)
|
||||
panel.add_child(contents)
|
||||
var title := Label.new()
|
||||
title.text = resource_name
|
||||
title.add_theme_font_size_override("font_size", 12)
|
||||
title.add_theme_color_override("font_color", accent)
|
||||
contents.add_child(title)
|
||||
var body := Label.new()
|
||||
body.text = description + "\nZapas: " + _count.text
|
||||
body.custom_minimum_size.x = 240
|
||||
body.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
body.add_theme_font_size_override("font_size", 10)
|
||||
contents.add_child(body)
|
||||
return panel
|
||||
@ -1 +0,0 @@
|
||||
uid://c7o65mkccm8vf
|
||||
@ -1,30 +0,0 @@
|
||||
extends PanelContainer
|
||||
|
||||
var accent := Color("91dbea")
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
z_index = 1
|
||||
resized.connect(queue_redraw)
|
||||
minimum_size_changed.connect(func() -> void: _fit_popup.call_deferred())
|
||||
_fit_popup.call_deferred()
|
||||
|
||||
func _fit_popup() -> void:
|
||||
reset_size()
|
||||
var shell := get_parent()
|
||||
if shell is Control and shell.get_parent() is Window:
|
||||
shell.reset_size()
|
||||
shell = shell.get_parent()
|
||||
if shell is Window:
|
||||
# The engine popup otherwise retains its first, unwrapped text height.
|
||||
shell.size = Vector2i(get_combined_minimum_size().ceil()) + Vector2i(4, 4)
|
||||
|
||||
func _draw() -> void:
|
||||
# Crisp etched corner brackets and a top accent; no blurred shadow.
|
||||
var inset := 5.0
|
||||
var length := 12.0
|
||||
for corner in [Vector2(inset, inset), Vector2(size.x - inset, inset), Vector2(inset, size.y - inset), Vector2(size.x - inset, size.y - inset)]:
|
||||
var inward := Vector2(1 if corner.x < size.x * 0.5 else -1, 1 if corner.y < size.y * 0.5 else -1)
|
||||
draw_line(corner, corner + Vector2(inward.x * length, 0), accent, 1.5, true)
|
||||
draw_line(corner, corner + Vector2(0, inward.y * length), accent, 1.5, true)
|
||||
draw_line(Vector2(22, 1), Vector2(minf(size.x - 22, 112), 1), accent, 2, true)
|
||||
@ -1 +0,0 @@
|
||||
uid://dtfbtajrculf0
|
||||
@ -14,16 +14,7 @@ var planet: Node2D
|
||||
var _open_tween: Tween
|
||||
var _missile_button: Button
|
||||
|
||||
var _gamma_buy: Button
|
||||
|
||||
func _ready() -> void:
|
||||
_gamma_buy = Button.new()
|
||||
_gamma_buy.name = "BuyIrradiatedAmmunition"
|
||||
_gamma_buy.custom_minimum_size.y = 36
|
||||
_gamma_buy.add_theme_font_size_override("font_size", 12)
|
||||
_gamma_buy.focus_mode = Control.FOCUS_NONE
|
||||
$Center/Panel/Contents.add_child(_gamma_buy)
|
||||
_gamma_buy.pressed.connect(func() -> void: _inventory.buy_irradiated_ammunition())
|
||||
next_button.pressed.connect(func() -> void: next_level_requested.emit())
|
||||
buy_ammunition_button.pressed.connect(_buy_ammunition)
|
||||
reset_skills_button.pressed.connect(_reset_skills)
|
||||
@ -84,9 +75,6 @@ func _position_at_planet() -> void:
|
||||
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:
|
||||
if _gamma_buy != null:
|
||||
_gamma_buy.text = "KUP 10 NAPROMIENIOWANEJ — %d KREDYTÓW" % (15 * maxi(1, GameState.system_level))
|
||||
_gamma_buy.disabled = _inventory == null or not _inventory.can_buy_irradiated_ammunition()
|
||||
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
||||
_missile_button.text = "KUP +1 RAKIETĘ — %d KREDYTÓW" % (_inventory.get_missile_buy_cost() if _inventory else ShipInventory.MISSILE_BUY_BASE_COST)
|
||||
reset_skills_button.disabled = not GameState.captain.can_reset_skills()
|
||||
|
||||
@ -7,7 +7,6 @@ var _details: VBoxContainer
|
||||
var _parts: Label
|
||||
var _stock: Label
|
||||
var _ammo: Button
|
||||
var _gamma: Button
|
||||
var _missile: Button
|
||||
|
||||
func _ready() -> void:
|
||||
@ -22,7 +21,7 @@ func _ready() -> void:
|
||||
_toggle.text = "TWÓRZ ▾"
|
||||
_toggle.custom_minimum_size.y = 28
|
||||
_toggle.add_theme_font_size_override("font_size", 12)
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(_toggle, Color("efb568"))
|
||||
_toggle.focus_mode = Control.FOCUS_NONE
|
||||
_toggle.pressed.connect(_toggle_expanded)
|
||||
contents.add_child(_toggle)
|
||||
_details = VBoxContainer.new()
|
||||
@ -37,8 +36,6 @@ func _ready() -> void:
|
||||
_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())
|
||||
_gamma = _button("CraftGamma", "+10 NAPROMIENIOWANEJ · 1 URAN + 10 CZĘŚCI")
|
||||
_gamma.pressed.connect(func() -> void: _inventory.craft_irradiated_ammunition())
|
||||
_details.hide()
|
||||
if bool(GameState.hud_panel_state.get("crafting_expanded", false)):
|
||||
_toggle_expanded()
|
||||
@ -73,6 +70,4 @@ 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()
|
||||
_gamma.disabled = not _inventory.can_craft_irradiated_ammunition()
|
||||
_stock.text += "\nNAPROMIENIOWANA: %d · URAN: %d" % [_inventory.irradiated_ammunition, int(GameState.captain.minerals.get("uranium", 0))]
|
||||
_missile.disabled = not _inventory.can_craft_missile()
|
||||
|
||||
@ -6,18 +6,20 @@ const CARGO_SIZE := 20
|
||||
@onready var cargo_grid: GridContainer = $Contents/CargoGrid
|
||||
@onready var close_button: Button = $Contents/Header/CloseButton
|
||||
@onready var title_label: Label = $Contents/Header/Title
|
||||
@onready var ammunition_label: Label = $Contents/Ammunition/Count
|
||||
|
||||
var _inventory: ShipInventory
|
||||
var _drawer_open := false
|
||||
var _slide_tween: Tween
|
||||
var _resource_cards: Dictionary = {}
|
||||
var _minerals_label: Label
|
||||
var drawer_width := 560.0
|
||||
|
||||
func _ready() -> void:
|
||||
close_button.pressed.connect(close_drawer)
|
||||
preload("res://scripts/ui/hud_button_style.gd").apply(close_button, Color("91dbea"))
|
||||
close_button.add_theme_font_size_override("font_size", 10)
|
||||
_create_resource_section()
|
||||
_minerals_label = Label.new()
|
||||
_minerals_label.add_theme_font_size_override("font_size", 10)
|
||||
$Contents.add_child(_minerals_label)
|
||||
$Contents.move_child(_minerals_label, $Contents/CargoGrid.get_index())
|
||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||
if _inventory:
|
||||
_inventory.inventory_changed.connect(_refresh_title)
|
||||
@ -32,75 +34,10 @@ func _ready() -> void:
|
||||
_refresh_title()
|
||||
|
||||
func _refresh_title() -> void:
|
||||
for key in ["iron", "titanium", "aluminium", "uranium"]:
|
||||
_resource_cards[key].set_amount(float(GameState.captain.minerals.get(key, 0)))
|
||||
_resource_cards["parts"].set_amount(GameState.captain.parts)
|
||||
_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)]
|
||||
if _inventory:
|
||||
title_label.text = "MAGAZYN · %d / %d" % [_inventory.get_cargo_used(), CARGO_SIZE]
|
||||
_resource_cards["ammunition"].set_amount(_inventory.ammunition)
|
||||
_resource_cards["irradiated_ammunition"].set_amount(_inventory.irradiated_ammunition)
|
||||
_resource_cards["missile"].set_amount(_inventory.get_missile_count())
|
||||
|
||||
func _create_resource_section() -> void:
|
||||
var frame := PanelContainer.new()
|
||||
frame.name = "ResourceSection"
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = Color("101e2d")
|
||||
style.border_color = Color("2d4c60")
|
||||
style.set_border_width_all(1)
|
||||
style.set_corner_radius_all(5)
|
||||
style.set_content_margin_all(8)
|
||||
frame.add_theme_stylebox_override("panel", style)
|
||||
$Contents.add_child(frame)
|
||||
$Contents.move_child(frame, cargo_grid.get_index())
|
||||
var section := VBoxContainer.new()
|
||||
section.name = "Resources"
|
||||
section.add_theme_constant_override("separation", 6)
|
||||
frame.add_child(section)
|
||||
var minerals := _resource_row(section, "SUROWCE", Color("d4b58a"))
|
||||
for data in [
|
||||
["iron", "Żelazo", "Surowiec pozyskiwany z asteroid.", Color("c5b5a0")],
|
||||
["titanium", "Tytan", "Surowiec pozyskiwany z asteroid.", Color("9ecbe9")],
|
||||
["aluminium", "Aluminium", "Surowiec pozyskiwany z asteroid.", Color("dce8ef")],
|
||||
["uranium", "Uran", "Surowiec z asteroid. Do produkcji napromieniowanej amunicji.", Color("a9ef83")],
|
||||
["parts", "Części", "Odzyskiwane z przedmiotów i wraków. Do produkcji amunicji i napraw.", Color("efb568")],
|
||||
]:
|
||||
_add_resource_card(minerals, data)
|
||||
var ammunition := _resource_row(section, "AMUNICJA", Color("91dbea"))
|
||||
for data in [
|
||||
["ammunition", "Zwykła amunicja", "Pociski do działka maszynowego. Obrażenia kinetyczne.", Color("efb568")],
|
||||
["irradiated_ammunition", "Napromieniowana amunicja", "Kapsuły do działka gamma. Obrażenia radiacyjne.", Color("a9ef83")],
|
||||
["missile", "Rakiety", "Amunicja do wyrzutni rakiet. Obrażenia kinetyczne.", Color("ffac8b")],
|
||||
]:
|
||||
_add_resource_card(ammunition, data)
|
||||
var cargo_title := Label.new()
|
||||
cargo_title.text = "PRZEDMIOTY"
|
||||
cargo_title.add_theme_font_size_override("font_size", 10)
|
||||
cargo_title.add_theme_color_override("font_color", Color("91dbea"))
|
||||
$Contents.add_child(cargo_title)
|
||||
$Contents.move_child(cargo_title, cargo_grid.get_index())
|
||||
|
||||
func _resource_row(section: VBoxContainer, caption: String, color: Color) -> HBoxContainer:
|
||||
var title := Label.new()
|
||||
title.text = caption
|
||||
title.add_theme_font_size_override("font_size", 10)
|
||||
title.add_theme_color_override("font_color", color)
|
||||
section.add_child(title)
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 5)
|
||||
section.add_child(row)
|
||||
return row
|
||||
|
||||
func _add_resource_card(row: HBoxContainer, data: Array) -> void:
|
||||
var card := PanelContainer.new()
|
||||
card.set_script(preload("res://scripts/ui/inventory_resource_card.gd"))
|
||||
card.name = str(data[0]).to_pascal_case()
|
||||
card.set("resource_name", data[1])
|
||||
card.set("description", data[2])
|
||||
card.set("accent", data[3])
|
||||
card.set("icon_texture", load("res://assets/icons/resources/%s.png" % data[0]))
|
||||
row.add_child(card)
|
||||
_resource_cards[data[0]] = card
|
||||
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()]
|
||||
|
||||
func toggle_drawer() -> void:
|
||||
_set_drawer_open(not _drawer_open)
|
||||
|
||||
@ -10,7 +10,7 @@ const BALANCE := preload("res://scripts/captain/captain_balance.gd")
|
||||
class DamageReceiver:
|
||||
extends Node2D
|
||||
var hits: Array[Dictionary] = []
|
||||
func take_weapon_hit(amount: float, critical: bool, _damage_type: int = 0) -> void:
|
||||
func take_weapon_hit(amount: float, critical: bool) -> void:
|
||||
hits.append({"damage": amount, "critical": critical})
|
||||
|
||||
func _ready() -> void:
|
||||
|
||||
@ -4,15 +4,12 @@ const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
||||
const DATABASE := preload("res://resources/items/affix_database.tres")
|
||||
|
||||
func _ready() -> void:
|
||||
assert(DATABASE.affixes.size() == 15)
|
||||
assert(DATABASE.affixes.size() == 10)
|
||||
for level in [1, 50, 1000]:
|
||||
for tier in [0, 1, 2]:
|
||||
for sample in 50:
|
||||
var item := GENERATOR.generate(level, tier)
|
||||
assert(item.item_level == level)
|
||||
if item.definition.category == ItemDefinition.Category.ACTIVE_EXTENSION:
|
||||
assert(item.additional_modifiers.is_empty())
|
||||
continue
|
||||
assert(item.additional_modifiers.size() >= 1 and item.additional_modifiers.size() <= 5)
|
||||
if tier == 2:
|
||||
assert(item.additional_modifiers.size() >= 4)
|
||||
@ -21,9 +18,9 @@ func _ready() -> void:
|
||||
assert(modifier.affix.can_roll(item.definition, level))
|
||||
assert(modifier.affix.affix_id not in ids)
|
||||
ids.append(modifier.affix.affix_id)
|
||||
var bounds := modifier.affix.get_value_range(level)
|
||||
assert(modifier.value >= bounds.x - 0.0001)
|
||||
assert(modifier.value <= bounds.y + 0.0001)
|
||||
var progression := float(level - 1) / 999.0
|
||||
assert(modifier.value >= lerpf(modifier.affix.minimum_value_level_1, modifier.affix.minimum_value_level_1000, progression))
|
||||
assert(modifier.value <= lerpf(modifier.affix.maximum_value_level_1, modifier.affix.maximum_value_level_1000, progression))
|
||||
assert(item.get_tooltip_text().contains(item.additional_modifiers[0].affix.display_name))
|
||||
|
||||
var weapon := ItemDefinition.new()
|
||||
|
||||
@ -22,7 +22,7 @@ func _ready() -> void:
|
||||
enemy.set("_player", ship)
|
||||
enemy.call("apply_level_settings", 4, 2)
|
||||
var expected := roundi(BALANCE.KILL_CREDITS[2] * 1.15 * 1.5)
|
||||
enemy.call("take_damage", 10.0 * (float(enemy.get("max_hull")) + float(enemy.get("max_shields"))))
|
||||
enemy.call("take_damage", enemy.get("max_hull"))
|
||||
assert(GameState.captain.credits == 0)
|
||||
assert(GameState.captain.level > 1 or GameState.captain.experience > 0)
|
||||
await get_tree().process_frame
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
GameState.system_seed = 12345
|
||||
assert(DamageTypes.for_weapon(ItemDefinition.WeaponKind.MACHINE_GUN) == DamageTypes.Type.KINETIC)
|
||||
assert(DamageTypes.for_weapon(ItemDefinition.WeaponKind.MISSILE) == DamageTypes.Type.KINETIC)
|
||||
assert(DamageTypes.for_weapon(ItemDefinition.WeaponKind.PLASMA) == DamageTypes.Type.ENERGY)
|
||||
assert(DamageTypes.for_weapon(ItemDefinition.WeaponKind.LASER) == DamageTypes.Type.ENERGY)
|
||||
assert(DamageTypes.for_weapon(ItemDefinition.WeaponKind.GAMMA) == DamageTypes.Type.RADIATION)
|
||||
var capped := DamageTypes.capped(Vector3(40, 40, 40))
|
||||
assert(capped.is_equal_approx(Vector3(20, 20, 20)))
|
||||
for level in [1, 500, 1000]:
|
||||
var profile := DamageTypes.enemy_profile(level, 12345)
|
||||
assert(profile == DamageTypes.enemy_profile(level, 12345))
|
||||
var values: Vector3 = profile["absorption"]
|
||||
assert(values.x + values.y + values.z <= 60.001)
|
||||
if level == 1:
|
||||
assert(is_equal_approx(values.x + values.y + values.z, 2.0))
|
||||
var ship := preload("res://scenes/game/player_ship.tscn").instantiate()
|
||||
add_child(ship)
|
||||
ship.set_physics_process(false)
|
||||
ship.get_node("WeaponController").set_physics_process(false)
|
||||
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||
var module := ItemInstance.new()
|
||||
module.definition = preload("res://resources/items/hull_plating.tres")
|
||||
var modifier := ItemStatModifier.new()
|
||||
modifier.stat_key = "kinetic_absorption"
|
||||
modifier.value = 20.0
|
||||
module.additional_modifiers.append(modifier)
|
||||
assert(inventory.add_item(module))
|
||||
assert(inventory.move_item("cargo", inventory.cargo.find(module), "module", 1))
|
||||
assert(is_equal_approx(ship.absorption.x, 20.0))
|
||||
ship.shields = 100.0
|
||||
ship.take_damage(10.0, false, DamageTypes.Type.KINETIC)
|
||||
assert(is_equal_approx(ship.shields, 92.0))
|
||||
assert(inventory.move_item("module", 1, "cargo", inventory.cargo.find(null)))
|
||||
assert(ship.absorption == Vector3.ZERO)
|
||||
GameState.captain.parts = 10
|
||||
GameState.captain.minerals["uranium"] = 1
|
||||
assert(inventory.craft_irradiated_ammunition())
|
||||
assert(inventory.irradiated_ammunition == 10)
|
||||
assert(not inventory.craft_irradiated_ammunition())
|
||||
assert(inventory.consume_irradiated_ammunition())
|
||||
GameState.captain.credits = 15
|
||||
assert(inventory.buy_irradiated_ammunition())
|
||||
assert(inventory.irradiated_ammunition == 19)
|
||||
inventory.preserve_for_restart()
|
||||
assert(GameState.restart_inventory["irradiated_ammunition"] == 19)
|
||||
var enemy := preload("res://scenes/game/enemy_ship.tscn").instantiate()
|
||||
enemy.apply_level_settings(1, 0)
|
||||
add_child(enemy)
|
||||
enemy.set_physics_process(false)
|
||||
enemy.absorption = Vector3(20, 0, 0)
|
||||
enemy.shields = 10
|
||||
enemy.hull = 100
|
||||
enemy.take_damage(20, false, DamageTypes.Type.KINETIC)
|
||||
assert(is_equal_approx(enemy.shields, 0))
|
||||
assert(is_equal_approx(enemy.hull, 94))
|
||||
enemy.take_damage(10, false, DamageTypes.Type.ENERGY)
|
||||
assert(is_equal_approx(enemy.hull, 84))
|
||||
var projectile := preload("res://scenes/game/weapon_projectile.tscn").instantiate()
|
||||
projectile.weapon_kind = ItemDefinition.WeaponKind.GAMMA
|
||||
projectile.damage = 8
|
||||
add_child(projectile)
|
||||
projectile.set_physics_process(false)
|
||||
projectile._apply_damage_once(enemy)
|
||||
assert(is_equal_approx(enemy.hull, 76))
|
||||
var status: Node = enemy.get_node("RadiationStatus")
|
||||
status.set_physics_process(false)
|
||||
for index in 6:
|
||||
status._physics_process(0.5)
|
||||
assert(is_equal_approx(enemy.hull, 70))
|
||||
assert(is_equal_approx(status.remaining, 0))
|
||||
assert(enemy.get_node("Sprite2D").modulate == Color.WHITE)
|
||||
for kind in 5:
|
||||
enemy.weapon_kind = kind
|
||||
enemy._fire_plasma(Vector2.RIGHT)
|
||||
for key in ["kinetic", "energy", "radiation"]:
|
||||
var affix: ItemAffixDefinition = load("res://resources/items/affixes/%s_absorption.tres" % key)
|
||||
assert(is_equal_approx(affix.roll_value(1), 1.0))
|
||||
assert(preload("res://resources/items/gamma_cannon.tres") in preload("res://scripts/items/item_generator.gd").DEFINITIONS)
|
||||
print("DAMAGE_TYPES_TEST: PASS (types, caps, profiles, crafting, purchase, persistence, shield overflow, radiation duration)")
|
||||
get_tree().quit()
|
||||
@ -1 +0,0 @@
|
||||
uid://b2tol3o50xrk7
|
||||
@ -1,4 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/items/damage_types_test.gd" id="1"]
|
||||
[node name="DamageTypesTest" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
@ -1,32 +0,0 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
seed(56789)
|
||||
var ship := preload("res://scenes/game/player_ship.tscn").instantiate()
|
||||
add_child(ship)
|
||||
ship.set_physics_process(false)
|
||||
ship.get_node("WeaponController").set_physics_process(false)
|
||||
ship.shields = 1000.0
|
||||
ship.max_shields = 1000.0
|
||||
var enemy := preload("res://scenes/game/enemy_ship.tscn").instantiate()
|
||||
enemy.position = Vector2(400, 0)
|
||||
add_child(enemy)
|
||||
enemy.set_physics_process(false)
|
||||
enemy.set("_player", ship)
|
||||
enemy.weapon_kind = ItemDefinition.WeaponKind.LASER
|
||||
enemy.weapon_damage = 1.0
|
||||
enemy.weapon_cooldown = 1.5
|
||||
assert(is_equal_approx(enemy.get_fire_interval(), 3.0))
|
||||
assert(is_equal_approx(enemy.get_weapon_dps(), 1.0 / 3.0))
|
||||
enemy.weapon_cooldown = 0.275
|
||||
assert(enemy.get_fire_interval() >= 1.4)
|
||||
await get_tree().physics_frame
|
||||
await get_tree().physics_frame
|
||||
for index in 100:
|
||||
enemy._fire_plasma(Vector2.LEFT)
|
||||
var hits := 1000.0 - float(ship.shields)
|
||||
assert(hits >= 45.0 and hits <= 85.0)
|
||||
print("ENEMY_LASER_TEST: PASS (slower cooldown, minimum interval, displayed DPS, %d real hits / 100 shots)" % roundi(hits))
|
||||
await get_tree().create_timer(0.15).timeout
|
||||
get_tree().quit()
|
||||
@ -1 +0,0 @@
|
||||
uid://ca6c7s2fwiptt
|
||||
@ -1,4 +0,0 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/items/enemy_laser_test.gd" id="1"]
|
||||
[node name="EnemyLaserTest" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
@ -49,7 +49,6 @@ func _ready() -> void:
|
||||
enemy.set("_player", ship)
|
||||
enemy.set("max_hull", 10000.0)
|
||||
enemy.set("hull", 10000.0)
|
||||
enemy.set("shields", 0.0)
|
||||
var controller := AimedGun.new()
|
||||
ship.add_child(controller)
|
||||
await get_tree().physics_frame
|
||||
|
||||
@ -73,5 +73,4 @@ func _enemy(ship: CharacterBody2D, hp: float) -> CharacterBody2D:
|
||||
enemy.set_physics_process(false)
|
||||
enemy.set("_player", ship)
|
||||
enemy.set("hull", hp)
|
||||
enemy.set("shields", 0.0)
|
||||
return enemy
|
||||
|
||||
@ -32,7 +32,7 @@ func _ready() -> void:
|
||||
addon.stat_key = "damage_percent"
|
||||
addon.value = 10.0
|
||||
stronger.additional_modifiers.append(addon)
|
||||
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE, ItemDefinition.WeaponKind.GAMMA]:
|
||||
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE]:
|
||||
assert(stronger.get_energy_cost() == 0.0)
|
||||
else:
|
||||
assert(stronger.get_energy_cost() > cost_before_addon)
|
||||
|
||||
@ -5,7 +5,6 @@ func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
GameState.system_seed = 314159
|
||||
var game := GAME.instantiate()
|
||||
assert(game.BOSS_SPAWN_DISTANCE >= 1800.0)
|
||||
add_child(game)
|
||||
game.set_physics_process(false)
|
||||
var player: CharacterBody2D = game.get_node("PlayerShip")
|
||||
|
||||
@ -210,9 +210,6 @@ func _assert_boss_and_health(game: Node2D) -> void:
|
||||
assert(boss.get_node("CollisionShape2D").scale == Vector2(2, 2))
|
||||
var bar: Node2D = boss.get_node("HealthBar")
|
||||
assert(is_equal_approx(bar.get_health_ratio(), 1.0))
|
||||
# Isolate the hull bar from the new shield and absorption layers.
|
||||
boss.shields = 0.0
|
||||
boss.absorption = Vector3.ZERO
|
||||
boss.take_damage(boss.max_hull * 0.5)
|
||||
assert(is_equal_approx(bar.get_health_ratio(), 0.5))
|
||||
boss.rotation = 1.2
|
||||
|
||||