Zmiany
40
artifacts/auxiliary_shield_preview.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://duf748rymyeaj"
|
||||
path="res://.godot/imported/auxiliary_shield_preview.png-0bf5fa47eebcce67a9a70141cf01d627.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/auxiliary_shield_preview.png"
|
||||
dest_files=["res://.godot/imported/auxiliary_shield_preview.png-0bf5fa47eebcce67a9a70141cf01d627.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/captain_skill_frames.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
40
artifacts/captain_skill_frames.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cw4l2lxdbjucg"
|
||||
path="res://.godot/imported/captain_skill_frames.png-02ff7181f7ea1e8a01da990a3fbf1110.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/captain_skill_frames.png"
|
||||
dest_files=["res://.godot/imported/captain_skill_frames.png-02ff7181f7ea1e8a01da990a3fbf1110.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/hermit_grounded_preview.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
40
artifacts/hermit_grounded_preview.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dqig2gbqb75bo"
|
||||
path="res://.godot/imported/hermit_grounded_preview.png-e0331a19a6ecc5450ce9860d1a140e6c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/hermit_grounded_preview.png"
|
||||
dest_files=["res://.godot/imported/hermit_grounded_preview.png-e0331a19a6ecc5450ce9860d1a140e6c.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/loot_drop_chime.wav
Normal file
24
artifacts/loot_drop_chime.wav.import
Normal file
@ -0,0 +1,24 @@
|
||||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://j5mmj3km55rg"
|
||||
path="res://.godot/imported/loot_drop_chime.wav-1bdfcd5d22ec333a22903baa0c3b008e.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/loot_drop_chime.wav"
|
||||
dest_files=["res://.godot/imported/loot_drop_chime.wav-1bdfcd5d22ec333a22903baa0c3b008e.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=false
|
||||
edit/loop_mode=0
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=2
|
||||
BIN
artifacts/loot_drop_effect.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
40
artifacts/loot_drop_effect.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dxgkab6udyujg"
|
||||
path="res://.godot/imported/loot_drop_effect.png-8de701186bf49f61df5525f5fe81fd9d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/loot_drop_effect.png"
|
||||
dest_files=["res://.godot/imported/loot_drop_effect.png-8de701186bf49f61df5525f5fe81fd9d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/ruins_loot_layout_fixed.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
40
artifacts/ruins_loot_layout_fixed.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b2e8uce47b1so"
|
||||
path="res://.godot/imported/ruins_loot_layout_fixed.png-951c69ac2e1a11208e8ee8692f77d461.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/ruins_loot_layout_fixed.png"
|
||||
dest_files=["res://.godot/imported/ruins_loot_layout_fixed.png-951c69ac2e1a11208e8ee8692f77d461.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
|
||||
16
artifacts/shield_performance_validation.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Shield rendering optimization
|
||||
|
||||
The polished shield previously rebuilt 34 antialiased arcs plus a filled circle per ship every frame. These primitives caused a large rendering cost in the Compatibility renderer.
|
||||
|
||||
Normal shields now share one 256 × 256 mipmapped texture and one shader material. The shader animates opacity; ordinary frames no longer rebuild shield geometry. Directional impact ripples still animate only while hits exist. Shield radius, collision interception, absorption and shield capacities are unchanged. Auxiliary shields retain their separate appearance and reuse the impact renderer without drawing a second normal shell.
|
||||
|
||||
Isolated benchmark, 120 full shields, 1280 × 720, OpenGL Compatibility, VSync disabled, 30 warm-up frames and 150 measured frames:
|
||||
|
||||
| Version | Mean frame time | Draw calls per frame |
|
||||
| --- | ---: | ---: |
|
||||
| Before | 221.991 ms | 12,360 |
|
||||
| Cached shell | 1.099 ms | 1 |
|
||||
|
||||
This is an isolated rendering stress test, not a measurement of complete gameplay FPS. Logs: `tmp/shield_perf_before.log` and `tmp/shield_perf_after.log`. Benchmark scene: `tests/previews/shield_performance_test.tscn`. The optional `--baseline` switch uses the saved pre-optimization script in `tmp/shield_visual_before_optimization.gd`.
|
||||
|
||||
Validation: shield collision test passes; graphical full/low/impact preview checked. Auxiliary-shield behavior tested separately.
|
||||
BIN
artifacts/shield_polish.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
40
artifacts/shield_polish.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://i8q5jedmns75"
|
||||
path="res://.godot/imported/shield_polish.png-eb5be9dbd6a0e5d078d9a4d5a6f13447.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/shield_polish.png"
|
||||
dest_files=["res://.godot/imported/shield_polish.png-eb5be9dbd6a0e5d078d9a4d5a6f13447.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
artifacts/single_visit_planet_poi.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
40
artifacts/single_visit_planet_poi.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://crkrqe7vseiwr"
|
||||
path="res://.godot/imported/single_visit_planet_poi.png-abb6b80346353d34f269319e3607adca.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/single_visit_planet_poi.png"
|
||||
dest_files=["res://.godot/imported/single_visit_planet_poi.png-abb6b80346353d34f269319e3607adca.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
20
artifacts/single_visit_planet_validation.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Single-visit planet POIs
|
||||
|
||||
Ordinary deposits, ruins, warehouses, abandoned villages and caves now grant their rewards immediately when visited with E. Each location can be collected once per expedition. Rewards remain in expedition cargo until a safe return; destruction still loses that expedition's cargo.
|
||||
|
||||
Question-mark events retain their decisions and existing rules. Engineers, cartographers, crew camps and deep deuterium deposits retain their own interfaces. E interacts on the surface; local strafing uses Q/R.
|
||||
|
||||
## Loot balance
|
||||
|
||||
Equipment bonus is 1 + 0.02 × average equipped breathing/suit/sidearm level, with each level capped at 50. Equipment also reduces corresponding environmental threats using the existing protection rules. Recovery is 1 − remaining total threat / 300, with a 15% minimum. Ordinary reward quantities use equipment bonus × recovery, rounded to whole units with a minimum of one. Mineral richness still uses the biome multiplier. Ruins yield 1–3 modules and adjust their level bonus for gear, environmental protection and biome richness.
|
||||
|
||||
## Verified
|
||||
|
||||
- `poi_rewards_test`: all five ordinary kinds, guaranteed single collection, duplicate safety, cargo delivery/loss, equipment/threat scaling and save round-trip.
|
||||
- `planet_threats_test`: environmental protection, special-event success curves and new loot scan.
|
||||
- `surface_events_test`: all ten event types, choices, costs and return behavior.
|
||||
- `planet_reward_scaling_test`: 30,000 module bonus rolls, 3,600 ruin visits and 600 mystery outcomes.
|
||||
- `single_visit_surface_test`: actual E interaction, reward dialog, repeat protection, pending cargo, service interfaces and question-mark event dialog.
|
||||
- `lander_flight_test`: movement, inertia, boost, shared ship parameters, E interaction and scan.
|
||||
|
||||
Graphical verification: `single_visit_planet_poi.png`, captured from the real surface screen at 1280 × 720.
|
||||
BIN
artifacts/time_engineer_grounded_preview.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
40
artifacts/time_engineer_grounded_preview.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cmlses7tg81ur"
|
||||
path="res://.godot/imported/time_engineer_grounded_preview.png-bb28daf34b7dc0f213abcdf8b735e1c0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://artifacts/time_engineer_grounded_preview.png"
|
||||
dest_files=["res://.godot/imported/time_engineer_grounded_preview.png-bb28daf34b7dc0f213abcdf8b735e1c0.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
|
||||
5
assets/planets/props/HERMIT_PROMPT.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Grounded hermit cartographer
|
||||
|
||||
Generated with the built-in imagegen tool, editing `hermit_cartographer.png`. Final asset: `hermit_cartographer_grounded.png`.
|
||||
|
||||
Edit this game building sprite for a top-down planetary exploration map. Preserve the recognizable hermit cartographer house: weathered teal domed roof, small satellite dish, rolled maps/crates and a small cyan mapping table. Change camera to near-overhead 75-80 degree aerial view, so mostly roof is visible and walls are very short, compatible with top-down terrain. Make it grounded, worn, subdued realistic hand-painted game art rather than glossy collectible icon. Natural soft upper-left daylight, restrained cyan accents, muted teal and dusty stone, no strong warm emissive interior. Small irregular foundation footprint, no circular pedestal, no terrain tile or rectangular ground patch, no thick outline. Very short soft contact shadow just under foundation, not long cast shadow. Standalone building centered with transparent background, generous transparent margins, no text, no UI, preserve genuinely transparent alpha. This is a replacement world sprite, not a UI icon.
|
||||
5
assets/planets/props/TIME_ENGINEER_PROMPT.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Grounded chronal engineer
|
||||
|
||||
Built-in imagegen edit of `time_engineer.png`, saved as `time_engineer_grounded.png`.
|
||||
|
||||
Edit the chronal engineer workshop sprite to fit a top-down planetary exploration map, consistent with a grounded worn painted game building. Preserve the teal barrel-shaped roof, brass pipes, compact cyan chronal crystal apparatus, small workbench. Change camera to steep near-overhead 75-80 degree aerial view, mostly roof with very short visible walls. Reduce saturation, avoid glossy collectible icon look, muted dusty teal/brass and natural soft upper-left daylight. No bright warm interior glow. Compact irregular foundation, no pedestal, no rectangular ground tile or terrain background. Short subtle contact shadow just beneath building, generous transparent margins. Standalone centered building with genuinely transparent alpha, no UI or text.
|
||||
BIN
assets/planets/props/hermit_cartographer_grounded.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
40
assets/planets/props/hermit_cartographer_grounded.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bui3ny5vvmjqs"
|
||||
path="res://.godot/imported/hermit_cartographer_grounded.png-036da8aeb38f328439846aad7b2fb31d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/planets/props/hermit_cartographer_grounded.png"
|
||||
dest_files=["res://.godot/imported/hermit_cartographer_grounded.png-036da8aeb38f328439846aad7b2fb31d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
assets/planets/props/time_engineer_grounded.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
40
assets/planets/props/time_engineer_grounded.png.import
Normal file
@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b7aeuc0dec5mu"
|
||||
path="res://.godot/imported/time_engineer_grounded.png-6c7ca763a18a068d3edeaa8b05b3cec3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/planets/props/time_engineer_grounded.png"
|
||||
dest_files=["res://.godot/imported/time_engineer_grounded.png-6c7ca763a18a068d3edeaa8b05b3cec3.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
|
||||
16
resources/effects/hermit_grounding.gdshader
Normal file
@ -0,0 +1,16 @@
|
||||
shader_type canvas_item;
|
||||
uniform vec4 ground_tint : source_color = vec4(0.4,0.35,0.25,1.0);
|
||||
varying vec4 vertex_tint;
|
||||
|
||||
void vertex() {
|
||||
vertex_tint = COLOR;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec4 art = texture(TEXTURE,UV);
|
||||
float light = dot(art.rgb,vec3(0.299,0.587,0.114));
|
||||
vec3 color = mix(vec3(light),art.rgb,0.78)*0.9;
|
||||
float footing = smoothstep(0.55,0.9,UV.y);
|
||||
color = mix(color,ground_tint.rgb*(0.45+light),0.12+footing*0.16);
|
||||
COLOR = vec4(color,art.a)*vertex_tint;
|
||||
}
|
||||
1
resources/effects/hermit_grounding.gdshader.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bon0cmiaqj514
|
||||
@ -10,7 +10,8 @@ icon = ExtResource("icon")
|
||||
item_id = "reinforced_shield"
|
||||
display_name = "Tarcze"
|
||||
category = 1
|
||||
description = "Zwiększa maksymalną pojemność tarcz."
|
||||
description = "Zwiększa maksymalną pojemność tarcz i stale je regeneruje."
|
||||
primary_stat = "max_shields"
|
||||
primary_value = 30.0
|
||||
shield_regeneration_bonus = 2.0
|
||||
stat_suffix = " tarcz"
|
||||
|
||||
@ -10,7 +10,8 @@ icon = ExtResource("icon")
|
||||
item_id = "shield_recharger"
|
||||
display_name = "Tarcze"
|
||||
category = 1
|
||||
description = "Zwiększa maksymalną pojemność tarcz statku."
|
||||
description = "Zwiększa maksymalną pojemność tarcz statku i stale je regeneruje."
|
||||
primary_stat = "max_shields"
|
||||
primary_value = 15.0
|
||||
shield_regeneration_bonus = 2.0
|
||||
stat_suffix = " tarczy"
|
||||
|
||||
8
resources/ui/shield_shell.gdshader
Normal file
@ -0,0 +1,8 @@
|
||||
shader_type canvas_item;
|
||||
render_mode unshaded;
|
||||
|
||||
void fragment() {
|
||||
vec4 shell = COLOR;
|
||||
shell.a *= 0.88 + 0.12 * sin(TIME * 1.8);
|
||||
COLOR = shell;
|
||||
}
|
||||
1
resources/ui/shield_shell.gdshader.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://r0qkep3cb68g
|
||||
@ -1,5 +1,8 @@
|
||||
extends "res://scripts/game/shield_visual.gd"
|
||||
|
||||
func _uses_cached_shell() -> bool:
|
||||
return false
|
||||
|
||||
func _draw() -> void:
|
||||
if current_shields > 0.0:
|
||||
var ratio := clampf(current_shields/max_shields,0.0,1.0)
|
||||
@ -23,4 +26,4 @@ func _draw() -> void:
|
||||
draw_string(ThemeDB.fallback_font,Vector2(-65,-shield_radius-12),"OSŁONA %.0f / %.0f" % [current_shields,max_shields],HORIZONTAL_ALIGNMENT_CENTER,130,11,Color("d7bfff"))
|
||||
draw_set_transform(Vector2.ZERO)
|
||||
# Keep the existing directional impact ripples on the larger perimeter.
|
||||
if not _hits.is_empty(): super._draw()
|
||||
if not _hits.is_empty(): _draw_impacts()
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
extends Label
|
||||
|
||||
const DISPLAY_DURATION := 1.3
|
||||
|
||||
@export var text_color := Color(1.0, 0.78, 0.28, 1.0)
|
||||
@export var is_critical := false
|
||||
@export var is_evade := false
|
||||
@ -16,7 +18,7 @@ func _ready() -> void:
|
||||
create_tween().tween_property(self, "scale", Vector2.ONE, 0.18).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
||||
var tween := create_tween()
|
||||
tween.set_parallel(true)
|
||||
tween.tween_property(self, "position:y", position.y - 48.0, 0.8).set_ease(Tween.EASE_OUT)
|
||||
tween.tween_property(self, "modulate:a", 0.0, 0.8).set_ease(Tween.EASE_IN)
|
||||
tween.tween_property(self, "position:y", position.y - 48.0, DISPLAY_DURATION).set_ease(Tween.EASE_OUT)
|
||||
tween.tween_property(self, "modulate:a", 0.0, DISPLAY_DURATION).set_ease(Tween.EASE_IN)
|
||||
tween.set_parallel(false)
|
||||
tween.tween_callback(queue_free)
|
||||
|
||||
@ -5,14 +5,58 @@ var max_shields := 100.0
|
||||
var _hit_flash_timer := 0.0
|
||||
var _hits: Array[Dictionary] = []
|
||||
var _time := 0.0
|
||||
static var _shell_texture: ImageTexture
|
||||
static var _shell_material: ShaderMaterial
|
||||
var _shell: Sprite2D
|
||||
|
||||
static func shell_texture() -> ImageTexture:
|
||||
if _shell_texture != null: return _shell_texture
|
||||
var image := Image.create(256,256,false,Image.FORMAT_RGBA8)
|
||||
# Build the soft rim once; every ship shares this texture and material.
|
||||
for y in 256:
|
||||
for x in 256:
|
||||
var point := (Vector2(x,y)+Vector2.ONE*0.5-Vector2.ONE*128.0)/112.0
|
||||
var radius := point.length()
|
||||
var edge := absf(radius-1.0)
|
||||
var alpha := exp(-pow(edge/0.010,2.0))*0.34
|
||||
alpha += exp(-pow(edge/0.05,2.0))*0.075
|
||||
if radius < 1.0: alpha += 0.012+exp(-pow(edge/0.09,2.0))*0.025
|
||||
var highlight := pow(maxf(0.0,cos(point.angle()*3.0)),24.0)
|
||||
alpha += exp(-pow(edge/0.016,2.0))*highlight*0.18
|
||||
image.set_pixel(x,y,Color(1,1,1,clampf(alpha,0.0,1.0)))
|
||||
image.generate_mipmaps()
|
||||
_shell_texture = ImageTexture.create_from_image(image)
|
||||
return _shell_texture
|
||||
|
||||
func _uses_cached_shell() -> bool:
|
||||
return true
|
||||
|
||||
func _sync_shell() -> void:
|
||||
if _shell == null: return
|
||||
_shell.visible = current_shields > 0.0
|
||||
_shell.scale = Vector2.ONE*shield_radius/112.0
|
||||
var ratio := clampf(current_shields/max_shields,0.0,1.0)
|
||||
_shell.self_modulate = Color(Color("61d8ff").lerp(Color("a4edff"),ratio*0.35),0.35+ratio*0.65)
|
||||
|
||||
func _ready() -> void:
|
||||
if _uses_cached_shell():
|
||||
_shell = Sprite2D.new()
|
||||
_shell.name = "CachedShieldShell"
|
||||
_shell.texture = shell_texture()
|
||||
_shell.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
||||
if _shell_material == null:
|
||||
_shell_material = ShaderMaterial.new()
|
||||
_shell_material.shader = preload("res://resources/ui/shield_shell.gdshader")
|
||||
_shell.material = _shell_material
|
||||
add_child(_shell)
|
||||
_sync_shell()
|
||||
var owner := get_parent()
|
||||
if owner is CharacterBody2D and owner.has_method("take_damage"):
|
||||
owner.add_to_group("shielded_combatants")
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_time += delta
|
||||
var had_hits := not _hits.is_empty()
|
||||
_hit_flash_timer = maxf(0.0,_hit_flash_timer-delta)
|
||||
for i in range(_hits.size()-1,-1,-1):
|
||||
_hits[i].age += delta
|
||||
@ -20,13 +64,16 @@ func _process(delta: float) -> void:
|
||||
visible = current_shields > 0.0 or not _hits.is_empty()
|
||||
var owner := get_parent()
|
||||
if owner.has_method("is_mini_boosting") and bool(owner.get("_is_destroyed")): visible = false
|
||||
if visible: queue_redraw()
|
||||
# Only impacts rebuild geometry. The GPU pulses the cached ambient shell.
|
||||
if had_hits or (visible and not _uses_cached_shell()): queue_redraw()
|
||||
|
||||
func set_shield_values(current: float, maximum: float) -> void:
|
||||
var changed := current_shields != current or max_shields != maxf(1.0,maximum)
|
||||
current_shields = current
|
||||
max_shields = maxf(1.0,maximum)
|
||||
visible = current_shields > 0.0 or not _hits.is_empty()
|
||||
queue_redraw()
|
||||
_sync_shell()
|
||||
if changed and not _uses_cached_shell(): queue_redraw()
|
||||
|
||||
func flash_hit(world_point := Vector2.INF, damage_type := DamageTypes.Type.ENERGY, strength := 1.0) -> void:
|
||||
_hit_flash_timer = 0.22
|
||||
@ -38,11 +85,9 @@ func flash_hit(world_point := Vector2.INF, damage_type := DamageTypes.Type.ENERG
|
||||
queue_redraw()
|
||||
|
||||
func _draw() -> void:
|
||||
var ratio := clampf(current_shields/max_shields,0.0,1.0)
|
||||
if current_shields>0:
|
||||
var ambient := 0.025+sin(_time*1.6)*0.008
|
||||
draw_arc(Vector2.ZERO,shield_radius,0,TAU,80,Color(0.25,0.7,1,0.10+ratio*0.13),0.8,true)
|
||||
draw_arc(Vector2.ZERO,shield_radius-1.0,0,TAU,80,Color(0.12,0.6,1,ambient),4.0,true)
|
||||
_draw_impacts()
|
||||
|
||||
func _draw_impacts() -> void:
|
||||
for hit in _hits:
|
||||
var t := float(hit.age)/0.42
|
||||
var fade := (1.0-t)*(1.0-t)*float(hit.strength)
|
||||
@ -53,6 +98,7 @@ func _draw() -> void:
|
||||
for layer in 3:
|
||||
draw_arc(Vector2.ZERO,radius-float(layer)*1.5,angle-spread,angle+spread,28,Color(color,fade*(0.6 if layer==0 else 0.13)),1.4 if layer==0 else 3.0,true)
|
||||
var contact := Vector2.RIGHT.rotated(angle)*shield_radius
|
||||
draw_circle(contact,8.0*(1.0-t),Color(color,fade*0.12))
|
||||
for ring in 2:
|
||||
draw_arc(contact,3.0+t*(17.0+ring*8.0),angle+PI*0.5,angle+PI*1.5,22,Color(color,fade*(0.5 if ring==0 else 0.17)),1.1,true)
|
||||
if t<0.35:
|
||||
|
||||
@ -16,6 +16,7 @@ func _ready() -> void:
|
||||
_label.add_theme_font_size_override("font_size",12)
|
||||
_label.text = preload("res://scripts/items/special_orbs.gd").NAMES[str(payload.orb)] if payload.has("orb") else "Mapa odległych systemów · poz. %d" % int(payload.map.level)
|
||||
add_child(_label)
|
||||
preload("res://scripts/items/loot_reveal_effect.gd").spawn(get_parent(),position,Color("b991ff"),3)
|
||||
func _process(delta: float) -> void:
|
||||
_time += delta
|
||||
queue_redraw()
|
||||
|
||||
@ -18,6 +18,7 @@ func get_damage_type() -> int:
|
||||
@export var primary_value: float = 0.0
|
||||
@export var stat_suffix: String = ""
|
||||
@export var energy_regeneration_bonus: float = 0.0
|
||||
@export var shield_regeneration_bonus: float = 0.0
|
||||
@export var weapon_kind: WeaponKind = WeaponKind.PLASMA
|
||||
@export var fire_interval: float = 0.25
|
||||
@export var weapon_cooldown: float = 0.0
|
||||
|
||||
@ -81,6 +81,8 @@ static func roll_base_values(item: ItemInstance, level: int) -> void:
|
||||
item.damage_max = maxf(item.damage_min + 1.0, roundf((lower + spread) * scale_factor))
|
||||
item.primary_value_override = (item.damage_min + item.damage_max) * 0.5
|
||||
item.energy_regeneration_override = definition.energy_regeneration_bonus * scale_factor * randf_range(0.8, 1.2)
|
||||
if definition.shield_regeneration_bonus > 0.0:
|
||||
item.shield_regeneration_override = definition.shield_regeneration_bonus * scale_factor * randf_range(0.8, 1.2)
|
||||
|
||||
static func can_advance(item: ItemInstance) -> bool:
|
||||
return item != null and item.definition != null and item.definition.category != ItemDefinition.Category.CONSUMABLE and item.item_level >= 1 and item.item_level < 1000
|
||||
|
||||
@ -90,6 +90,7 @@ func get_active_ability() -> ActiveAbility:
|
||||
@export var additional_modifiers: Array[ItemStatModifier] = []
|
||||
@export var primary_value_override: float = -1.0
|
||||
@export var energy_regeneration_override: float = -1.0
|
||||
@export var shield_regeneration_override: float = -1.0
|
||||
@export_range(0, 4) var rarity: int = 0
|
||||
@export var damage_min: float = -1.0
|
||||
@export var damage_max: float = -1.0
|
||||
@ -103,11 +104,19 @@ func get_stat_total(stat_key: String) -> float:
|
||||
total += primary_value_override if primary_value_override >= 0.0 else definition.primary_value
|
||||
if definition and stat_key == "energy_regeneration":
|
||||
total += energy_regeneration_override if energy_regeneration_override >= 0.0 else definition.energy_regeneration_bonus
|
||||
if definition and stat_key == "shield_regeneration":
|
||||
total += get_base_shield_regeneration()
|
||||
for modifier in additional_modifiers:
|
||||
if modifier and modifier.stat_key == stat_key:
|
||||
total += modifier.value
|
||||
return total * ENERGY_REGENERATION_BONUS_MULTIPLIER if stat_key == "energy_regeneration" else total
|
||||
|
||||
func get_base_shield_regeneration() -> float:
|
||||
if definition == null: return 0.0
|
||||
if shield_regeneration_override >= 0.0: return shield_regeneration_override
|
||||
# Previously acquired modules gain the new base property at their current level.
|
||||
return definition.shield_regeneration_bonus * preload("res://scripts/levels/level_balance.gd").item_stat_scale(item_level)
|
||||
|
||||
func get_damage_range() -> Vector2:
|
||||
if definition == null or definition.category != ItemDefinition.Category.WEAPON:
|
||||
return Vector2.ZERO
|
||||
@ -211,6 +220,8 @@ func get_tooltip_text() -> String:
|
||||
var lines: Array[String] = [definition.display_name, "%s • Poziom %d" % [get_rarity_name(), item_level], "", definition.description, "", "CECHA GŁÓWNA", primary_text]
|
||||
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.shield_regeneration_bonus > 0.0:
|
||||
lines.append("Regeneracja tarcz: +%.1f pkt/s" % get_base_shield_regeneration())
|
||||
if definition.category == ItemDefinition.Category.WEAPON:
|
||||
lines.append("Typ obrażeń: %s" % DamageTypes.NAMES[get_damage_type()])
|
||||
if definition.weapon_effect == "pulse_laser": lines.append("Prędkość lecącej wiązki: %.0f px/s" % definition.projectile_speed)
|
||||
|
||||
@ -21,6 +21,9 @@ func _ready() -> void:
|
||||
z_index = 18
|
||||
set_process(item.get_addon_count() >= 5)
|
||||
queue_redraw()
|
||||
preload("res://scripts/items/loot_reveal_effect.gd").spawn(get_parent(),position,item.get_rarity_color(),item.rarity)
|
||||
scale = Vector2.ONE*0.25
|
||||
create_tween().tween_property(self,"scale",Vector2.ONE,0.32).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_glow_time += delta
|
||||
|
||||
86
scripts/items/loot_reveal_effect.gd
Normal file
@ -0,0 +1,86 @@
|
||||
extends Node2D
|
||||
|
||||
const DURATION := 0.85
|
||||
static var _sounds: Dictionary = {}
|
||||
static var _last_sound_ms := -1000
|
||||
var tint := Color("91dbea")
|
||||
var quality := 0
|
||||
var age := 0.0
|
||||
|
||||
static func spawn(parent: Node, at: Vector2, color: Color, rarity: int = 0, screen_audio: bool = false) -> Node2D:
|
||||
var effect := Node2D.new()
|
||||
effect.set_script(load("res://scripts/items/loot_reveal_effect.gd"))
|
||||
effect.tint = color
|
||||
effect.quality = clampi(rarity,0,4)
|
||||
effect.position = at
|
||||
parent.add_child(effect)
|
||||
# Simultaneous drops share one chime, keeping battles from becoming too loud.
|
||||
var now := Time.get_ticks_msec()
|
||||
if now-_last_sound_ms >= 100:
|
||||
_last_sound_ms = now
|
||||
var audio: Node
|
||||
if screen_audio:
|
||||
audio = AudioStreamPlayer.new()
|
||||
else:
|
||||
audio = AudioStreamPlayer2D.new()
|
||||
audio.max_distance = 1200.0
|
||||
audio.attenuation = 1.5
|
||||
audio.stream = sound(quality_band(rarity))
|
||||
audio.volume_db = -12.0
|
||||
if AudioServer.get_bus_index("SFX") >= 0: audio.bus = &"SFX"
|
||||
effect.add_child(audio)
|
||||
audio.play()
|
||||
return effect
|
||||
|
||||
static func quality_band(rarity: int) -> int:
|
||||
return 1 if rarity >= 3 else 0
|
||||
|
||||
static func sound(band: int = 0) -> AudioStreamWAV:
|
||||
if _sounds.has(band): return _sounds[band]
|
||||
var rate := 22050
|
||||
var length := 0.65
|
||||
var data := PackedByteArray()
|
||||
data.resize(int(rate*length)*2)
|
||||
for index in int(rate*length):
|
||||
var t := float(index)/rate
|
||||
var value := 0.0
|
||||
for note in 3:
|
||||
var elapsed := t-note*0.075
|
||||
if elapsed < 0.0: continue
|
||||
var frequency: float = [659.25,830.61,987.77][note]*(1.25 if band > 0 else 1.0)
|
||||
var envelope := minf(elapsed/0.006,1.0)*exp(-elapsed*9.0)
|
||||
value += (sin(TAU*frequency*elapsed)+0.18*sin(TAU*frequency*2.0*elapsed))*envelope*0.18
|
||||
data.encode_s16(index*2,clampi(roundi(value*32767),-32768,32767))
|
||||
var stream := AudioStreamWAV.new()
|
||||
stream.format = AudioStreamWAV.FORMAT_16_BITS
|
||||
stream.mix_rate = rate
|
||||
stream.data = data
|
||||
_sounds[band] = stream
|
||||
return stream
|
||||
|
||||
func _ready() -> void:
|
||||
z_index = 30
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
age += delta
|
||||
if age >= DURATION:
|
||||
queue_free()
|
||||
return
|
||||
queue_redraw()
|
||||
|
||||
func _draw() -> void:
|
||||
var progress := clampf(age/DURATION,0.0,1.0)
|
||||
var fade := pow(1.0-progress,2.0)
|
||||
var radius := 16.0+75.0*(1.0-pow(1.0-progress,3.0))
|
||||
for layer in range(4,0,-1):
|
||||
draw_circle(Vector2.ZERO,12.0+layer*8.0,Color(tint,fade*0.035))
|
||||
draw_arc(Vector2.ZERO,radius,0,TAU,64,Color(tint,fade*0.8),1.4,true)
|
||||
for index in 14+quality*2:
|
||||
var angle := index*2.39996
|
||||
var direction := Vector2.from_angle(angle)
|
||||
var distance := (18.0+float(index%4)*8.0)+progress*(42.0+float(index%3)*18.0)
|
||||
var point := direction*distance
|
||||
draw_line(point,point-direction*(3.0+8.0*(1.0-progress)),Color(tint,fade),1.5,true)
|
||||
var beam := maxf(0.0,1.0-age/0.45)
|
||||
draw_line(Vector2(0,12),Vector2(0,-92-quality*12),Color(tint,beam*0.65),2.0,true)
|
||||
draw_line(Vector2(-10,0),Vector2(10,0),Color.WHITE*Color(1,1,1,beam),2.0,true)
|
||||
1
scripts/items/loot_reveal_effect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://552wjksemhnb
|
||||
@ -12,6 +12,7 @@ func _ready() -> void:
|
||||
add_to_group("time_crystal_pickups")
|
||||
_player = get_parent().get_node_or_null("PlayerShip") as CharacterBody2D
|
||||
z_index = 18
|
||||
preload("res://scripts/items/loot_reveal_effect.gd").spawn(get_parent(),position,Color("9be7ff"))
|
||||
|
||||
func _draw() -> void:
|
||||
for radius in [27.0,22.0,18.0]: draw_circle(Vector2.ZERO,radius,Color(0.42,0.86,1.0,0.07))
|
||||
|
||||
@ -174,7 +174,8 @@ func _layout_prompt() -> void:
|
||||
func _compact_scan(profile: Dictionary) -> String:
|
||||
var captain: Resource = GameState.captain
|
||||
var report: Dictionary = PROFILES.threat_report(profile,captain)
|
||||
return "%s · %s\nTLEN %d%% · TEMP %d°C · BIO %d/50\nZAGROŻENIE: %.1f%% / 300%%\nŚREDNIA SZANSA POI: %.1f%%\nEtapy: %.1f%% / %.1f%% / %.1f%%\nLądowanie −%d HP · Lądownik %d%%" % [profile.name,PROFILES.biome_name(profile),profile.oxygen,profile.temperature,profile.flora,report.total,PROFILES.average_success_chance(profile,captain)*100,PROFILES.success_chance(profile,captain,0)*100,PROFILES.success_chance(profile,captain,1)*100,PROFILES.success_chance(profile,captain,2)*100,profile.landing_damage,ceili(captain.expedition.lander_hp)]
|
||||
var loot := PROFILES.poi_loot_report(profile,captain)
|
||||
return "%s · %s\nTLEN %d%% · TEMP %d°C · BIO %d/50\nZAGROŻENIE: %.1f%% / 300%%\nŁUP POI: ×%.2f · odzysk %.0f%%\nPOI: podleć i naciśnij E\nLądowanie −%d HP · Lądownik %d%%" % [profile.name,PROFILES.biome_name(profile),profile.oxygen,profile.temperature,profile.flora,report.total,loot.multiplier,loot.recovery*100.0,profile.landing_damage,ceili(captain.expedition.lander_hp)]
|
||||
|
||||
|
||||
func _unhandled_key_input(event: InputEvent) -> void:
|
||||
|
||||
20
scripts/planets/hermit_ground_contact.gd
Normal file
@ -0,0 +1,20 @@
|
||||
extends Node2D
|
||||
|
||||
var soil := Color("615b45")
|
||||
|
||||
func _draw() -> void:
|
||||
# A small irregular worn footprint, with feathered edges instead of a ground tile.
|
||||
for layer in range(5,0,-1):
|
||||
var points := PackedVector2Array()
|
||||
for index in 40:
|
||||
var angle := TAU*index/40.0
|
||||
var irregular := 1.0+0.055*sin(angle*7.0)+0.035*cos(angle*11.0)
|
||||
points.append(Vector2(cos(angle)*49.0,sin(angle)*29.0)*irregular*(0.85+layer*0.045)+Vector2(0,17))
|
||||
draw_colored_polygon(points,Color(soil,0.04))
|
||||
# Short soft contact shadow beneath the building's foundation.
|
||||
for layer in range(4,0,-1):
|
||||
var points := PackedVector2Array()
|
||||
for index in 40:
|
||||
var angle := TAU*index/40.0
|
||||
points.append(Vector2(cos(angle)*(37.0+layer*1.6),sin(angle)*(16.0+layer*1.2))+Vector2(4,21))
|
||||
draw_colored_polygon(points,Color(0.04,0.045,0.03,0.055))
|
||||
1
scripts/planets/hermit_ground_contact.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://1hyakl7p27h5
|
||||
@ -62,6 +62,15 @@ static func threat_report(profile: Dictionary, captain: Resource) -> Dictionary:
|
||||
static func global_threat(profile: Dictionary, captain: Resource) -> float:
|
||||
return float(threat_report(profile,captain).total)
|
||||
|
||||
static func poi_loot_report(profile: Dictionary, captain: Resource) -> Dictionary:
|
||||
var gear := preload("res://scripts/planets/captain_equipment.gd")
|
||||
var equipped_levels := 0.0
|
||||
for kind in gear.KINDS: equipped_levels += clampi(gear.level(captain,kind),0,50)
|
||||
var gear_multiplier := 1.0+(equipped_levels/3.0)*0.02
|
||||
var threat := global_threat(profile,captain)
|
||||
var recovery := clampf(1.0-threat/300.0,0.15,1.0)
|
||||
return {"multiplier":gear_multiplier*recovery,"recovery":recovery,"gear_multiplier":gear_multiplier,"threat":threat}
|
||||
|
||||
static func success_chance(profile: Dictionary, captain: Resource, stage: int) -> float:
|
||||
var index := clampi(stage,0,2)
|
||||
var severity := clampf(global_threat(profile,captain)/150.0,0.0,1.0)
|
||||
@ -84,10 +93,10 @@ static func biome_name(profile: Dictionary) -> String:
|
||||
|
||||
static func scan_description(profile: Dictionary, captain: Resource) -> String:
|
||||
var report := threat_report(profile,captain)
|
||||
return "%s · %s\nTLEN %d%% · zagrożenie %.0f%% → %.0f%%\nTEMPERATURA %d°C · zagrożenie %.0f%% → %.0f%%\nBIOLOGICZNE %d/50 · zagrożenie %.0f%% → %.0f%%\nZAGROŻENIE GLOBALNE: %.1f%% / 300%%\nBez sprzętu: %.1f%% · redukcja 2 pp/poziom\nŚREDNIA SZANSA POI: %.1f%%\nEtapy POI: %.1f%% / %.1f%% / %.1f%%\nLądowanie: −%d HP · Lądownik: %d%%" % [
|
||||
var loot := poi_loot_report(profile,captain)
|
||||
return "%s · %s\nTLEN %d%% · zagrożenie %.0f%% → %.0f%%\nTEMPERATURA %d°C · zagrożenie %.0f%% → %.0f%%\nBIOLOGICZNE %d/50 · zagrożenie %.0f%% → %.0f%%\nZAGROŻENIE GLOBALNE: %.1f%% / 300%%\nBez sprzętu: %.1f%% · redukcja 2 pp/poziom\nŁUP POI: ×%.2f · odzysk %.0f%% · sprzęt ×%.2f\nPOI: podleć i naciśnij E, aby odebrać znaleziska.\nLądowanie: −%d HP · Lądownik: %d%%" % [
|
||||
profile.name,biome_name(profile),profile.oxygen,report.raw.oxygen,report.effective.oxygen,
|
||||
profile.temperature,report.raw.temperature,report.effective.temperature,
|
||||
profile.flora,report.raw.biology,report.effective.biology,
|
||||
report.total,report.raw_total,average_success_chance(profile,captain)*100.0,
|
||||
success_chance(profile,captain,0)*100.0,success_chance(profile,captain,1)*100.0,success_chance(profile,captain,2)*100.0,
|
||||
report.total,report.raw_total,loot.multiplier,loot.recovery*100.0,loot.gear_multiplier,
|
||||
profile.landing_damage,ceili(captain.expedition.lander_hp)]
|
||||
|
||||
@ -83,36 +83,19 @@ func add_material(key: String, amount: int) -> void:
|
||||
emit_changed()
|
||||
|
||||
func resolve_poi(captain: Resource, poi: Dictionary, rng: RandomNumberGenerator) -> Dictionary:
|
||||
if not active or bool(poi.get("complete", false)) or not preload("res://scripts/planets/poi_rules.gd").STAGES.has(str(poi.get("kind", ""))):
|
||||
var rules := preload("res://scripts/planets/poi_rules.gd")
|
||||
if not active or lander_hp <= 0.0 or bool(poi.get("complete", false)) or str(poi.get("kind", "")) not in rules.KINDS:
|
||||
return {}
|
||||
var stage := int(poi.get("stage", 0))
|
||||
var chance := PROFILES.success_chance(active_profile, captain, stage)
|
||||
var success := false
|
||||
var result := {"success": success, "chance": chance, "damage": 0, "materials": {}, "module": null}
|
||||
if chance <= 0.0:
|
||||
result.blocked = true
|
||||
result.reason = "Ten etap ma 0% szans. Potrzebujesz lepszego wyposażenia, aby zmniejszyć zagrożenie."
|
||||
return result
|
||||
success = rng.randf() < chance
|
||||
result.success = success
|
||||
if success:
|
||||
var reward: Dictionary = preload("res://scripts/planets/poi_rules.gd").reward(str(poi.kind),stage,rng,active_profile,captain)
|
||||
for key in reward:
|
||||
add_material(key,int(reward[key]))
|
||||
result.materials = reward
|
||||
poi.complete = true
|
||||
var result := {"success":true,"damage":0,"materials":rules.reward(str(poi.kind),rng,active_profile,captain),"module":null,"modules":[],"loot":PROFILES.poi_loot_report(active_profile,captain)}
|
||||
for key in result.materials: add_material(key,int(result.materials[key]))
|
||||
if str(poi.kind) == "ruins":
|
||||
var item: ItemInstance = REWARDS.generate_module(rng,active_profile,GameState.system_level,null,0,stage+1)
|
||||
for index in rules.module_count(active_profile,captain):
|
||||
var item: ItemInstance = REWARDS.generate_module(rng,active_profile,GameState.system_level,null,0,rules.module_bonus(rng,active_profile,captain))
|
||||
cargo_modules.append(item)
|
||||
result.module = item
|
||||
poi.stage = stage + 1
|
||||
if int(poi.stage) >= 3:
|
||||
poi.complete = true
|
||||
else:
|
||||
var loss := rng.randi_range(8, 15) + stage * 5 + roundi(float(active_profile.difficulty) * 10)
|
||||
damage(loss)
|
||||
result.damage = loss
|
||||
# Failure closes this location; previously collected loot stays until return.
|
||||
poi.complete = true
|
||||
result.modules.append(item)
|
||||
result.module = result.modules[0]
|
||||
poi["loot_result"] = result
|
||||
emit_changed()
|
||||
return result
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ static func button(parent: Node, content: String, action: Callable, primary := f
|
||||
parent.add_child(node)
|
||||
return node
|
||||
|
||||
static func header(parent: VBoxContainer, kind: String, stage: int, complete: bool) -> void:
|
||||
static func header(parent: VBoxContainer, kind: String, art_variant: int, complete: bool) -> void:
|
||||
var atlas: Texture2D = load("res://assets/planets/poi/expedition_atlas.png")
|
||||
var image := AtlasTexture.new()
|
||||
image.atlas = atlas
|
||||
@ -69,10 +69,10 @@ static func header(parent: VBoxContainer, kind: String, stage: int, complete: bo
|
||||
var row := ORDER.find(kind)
|
||||
var rows := [0.0,0.198,0.394,0.589,0.776,1.0]
|
||||
var extent := Vector2(atlas.get_size())
|
||||
image.region = Rect2(Vector2(stage/3.0,rows[row])*extent+Vector2(3,3),Vector2(extent.x/3.0,(rows[row+1]-rows[row])*extent.y)-Vector2(6,6))
|
||||
image.region = Rect2(Vector2(clampi(art_variant,0,2)/3.0,rows[row])*extent+Vector2(3,3),Vector2(extent.x/3.0,(rows[row+1]-rows[row])*extent.y)-Vector2(6,6))
|
||||
image.filter_clip = true
|
||||
var frame := PanelContainer.new()
|
||||
frame.custom_minimum_size.y = 164
|
||||
frame.custom_minimum_size.y = 132
|
||||
frame.clip_contents = true
|
||||
frame.add_theme_stylebox_override("panel",StyleBoxEmpty.new())
|
||||
var art := TextureRect.new()
|
||||
@ -82,9 +82,9 @@ static func header(parent: VBoxContainer, kind: String, stage: int, complete: bo
|
||||
art.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
||||
frame.add_child(art)
|
||||
parent.add_child(frame)
|
||||
text(parent,"DZIENNIK WYPRAWY / %s" % ("ZAKOŃCZONO" if complete else "ETAP %02d / 03" % (stage+1)),11,MUTED)
|
||||
text(parent,"DZIENNIK WYPRAWY / %s" % ("ODWIEDZONO" if complete else "MIEJSCE ODKRYTE"),11,MUTED)
|
||||
text(parent,str(RULES.NAMES[kind]),23,GOLD)
|
||||
text(parent,STORIES[kind][stage],14)
|
||||
if not complete: text(parent,STORIES[kind][clampi(art_variant,0,2)],14)
|
||||
var line := HSeparator.new()
|
||||
line.modulate = Color("7b8062")
|
||||
parent.add_child(line)
|
||||
|
||||
@ -1,34 +1,32 @@
|
||||
extends RefCounted
|
||||
const NAMES := {"deposit":"Złoże surowców", "ruins":"Starożytna struktura", "warehouse":"Opuszczony magazyn", "village":"Opuszczona wioska", "cave":"Jaskinia", "deep_deposit":"Głębokie złoże deuteru", "crew":"Obóz specjalisty", "hermit":"Pustelnik / Kartograf", "time_engineer":"Inżynier chronalny"}
|
||||
const STAGES := {
|
||||
"deposit":["Zbierz odsłonięte minerały", "Wykonaj odwiert", "Wydobądź głęboką żyłę"],
|
||||
"ruins":["Przeszukaj przedsionek", "Otwórz komorę", "Zbadaj rdzeń"],
|
||||
"warehouse":["Przeszukaj skrzynie", "Otwórz zbrojownię", "Odblokuj skarbiec zaopatrzenia"],
|
||||
"village":["Przeszukaj domy", "Odzyskaj dzienniki mieszkańców", "Otwórz sejf osady"],
|
||||
"cave":["Zbadaj wejście", "Zejdź do groty", "Pobierz próbki z głębi"]}
|
||||
const PREVIEWS := {
|
||||
"deposit":["Rzadkie surowce planetarne", "Więcej rzadkich surowców", "Dużo rzadkich surowców"],
|
||||
"ruins":["Moduł: poziom układu +1", "Moduł: poziom układu +2", "Moduł: poziom układu +3"],
|
||||
"warehouse":["40–70 amunicji", "100–160 amunicji i 2–4 rakiety", "180–260 amunicji, 4–7 rakiet lub 30–50 amunicji radiacyjnej oraz surowce kosmiczne"],
|
||||
"village":["30–60 kredytów", "80–140 kredytów + 10% brakującego EXP do awansu", "220–360 kredytów"],
|
||||
"cave":["1 próbka do analizy", "2 próbki do analizy", "4 próbki do analizy"]}
|
||||
const KINDS := ["deposit","ruins","warehouse","village","cave"]
|
||||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
const REWARDS := preload("res://scripts/planets/planet_rewards.gd")
|
||||
|
||||
static func reward(kind: String, stage: int, rng: RandomNumberGenerator, profile: Dictionary, captain: Resource) -> Dictionary:
|
||||
static func reward(kind: String, rng: RandomNumberGenerator, profile: Dictionary, captain: Resource) -> Dictionary:
|
||||
var result := {}
|
||||
var multiplier: float = PROFILES.poi_loot_report(profile,captain).multiplier
|
||||
match kind:
|
||||
"deposit":
|
||||
var keys: Array = preload("res://scripts/planets/planet_profiles.gd").MATERIALS
|
||||
result[keys[rng.randi_range(0,keys.size()-1)]] = roundi(rng.randi_range(5,12)*(1.0+stage*0.65)*preload("res://scripts/planets/planet_rewards.gd").material_multiplier(profile))
|
||||
var key: String = PROFILES.MATERIALS[rng.randi_range(0,PROFILES.MATERIALS.size()-1)]
|
||||
result[key] = rng.randi_range(18,28)*REWARDS.material_multiplier(profile)
|
||||
"warehouse":
|
||||
result.ammunition = rng.randi_range([40,100,180][stage],[70,160,260][stage])
|
||||
if stage == 1: result.missile = rng.randi_range(2,4)
|
||||
if stage == 2:
|
||||
if rng.randf() < 0.5: result.missile = rng.randi_range(4,7)
|
||||
else: result.irradiated_ammunition = rng.randi_range(30,50)
|
||||
result.ammunition = rng.randi_range(130,210)
|
||||
result.missile = rng.randi_range(2,4)
|
||||
if rng.randf() < 0.25: result.irradiated_ammunition = rng.randi_range(20,35)
|
||||
var keys := ["iron","titanium","aluminium","uranium","sulfur"]
|
||||
result[keys[rng.randi_range(0,4)]] = roundi(rng.randi_range(8,16)*preload("res://scripts/planets/planet_rewards.gd").material_multiplier(profile))
|
||||
result[keys[rng.randi_range(0,4)]] = rng.randi_range(8,16)*REWARDS.material_multiplier(profile)
|
||||
"village":
|
||||
result.credits = rng.randi_range([30,80,220][stage],[60,140,360][stage])
|
||||
if stage == 1: result.experience = maxi(1,ceili(maxi(0,captain.get_xp_required()-captain.experience)*0.1))
|
||||
"cave": result.samples = [1,2,4][stage]
|
||||
result.credits = rng.randi_range(140,220)
|
||||
result.experience = maxi(1,ceili(maxi(0,captain.get_xp_required()-captain.experience)*0.05))
|
||||
"cave": result.samples = rng.randi_range(3,5)
|
||||
for key in result: result[key] = maxi(1,roundi(float(result[key])*multiplier))
|
||||
return result
|
||||
|
||||
static func module_count(profile: Dictionary, captain: Resource) -> int:
|
||||
return clampi(roundi(1.5*float(PROFILES.poi_loot_report(profile,captain).multiplier)),1,3)
|
||||
|
||||
static func module_bonus(rng: RandomNumberGenerator, profile: Dictionary, captain: Resource) -> int:
|
||||
var report := PROFILES.poi_loot_report(profile,captain)
|
||||
return maxi(0,roundi(REWARDS.roll_module_bonus(rng,profile)*float(report.recovery)))+roundi((float(report.gear_multiplier)-1.0)*2.0)
|
||||
|
||||
@ -85,7 +85,7 @@ static func generate(seed_value: int, profile: Dictionary) -> Dictionary:
|
||||
if not found:
|
||||
# A lander can cross every terrain; a remote fallback never traps it.
|
||||
chosen = Vector2.from_angle(index * TAU / kinds.size()) * 1250
|
||||
pois.append({"id": index, "kind": kind, "position": chosen, "stage": 0, "complete": false, "discovered": false})
|
||||
pois.append({"id": index, "kind": kind, "position": chosen, "complete": false, "discovered": false})
|
||||
_attach_caves(pois,mountains)
|
||||
# Clear vegetation around explorable structures so entrances stay readable.
|
||||
for poi in pois:
|
||||
|
||||
@ -137,7 +137,7 @@ func _ready() -> void:
|
||||
help.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||
help.position = Vector2(24, size.y-84)
|
||||
POI_CARD.panel_style(help)
|
||||
POI_CARD.text(help, "W — ciąg · S — hamuj / wstecz · A/D — obrót\nQ/E — ruch boczny · TAB — dopalanie · F — zbadaj", 13)
|
||||
POI_CARD.text(help, "W — ciąg · S — hamuj / wstecz · A/D — obrót\nQ/R — ruch boczny · TAB — dopalanie · E — odwiedź POI", 13)
|
||||
var map_frame := UI.panel(self, Vector2(195,195))
|
||||
map_frame.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
||||
map_frame.position = size-Vector2(220,220)
|
||||
@ -171,7 +171,7 @@ func _physics_process(delta: float) -> void:
|
||||
return
|
||||
_motion.step(delta, Input.get_axis("ship_turn_left","ship_turn_right"),
|
||||
Input.is_action_pressed("ship_thrust"), Input.is_action_pressed("ship_brake"),
|
||||
Input.get_axis("ship_strafe_left","ship_strafe_right"), Input.is_action_pressed("ship_mini_boost"))
|
||||
float(Input.is_physical_key_pressed(KEY_R))-float(Input.is_physical_key_pressed(KEY_Q)), Input.is_action_pressed("ship_mini_boost"))
|
||||
lander.rotation = _motion.rotation
|
||||
var next := lander.position + _motion.velocity * delta
|
||||
var bounded := next.clamp(Vector2(-1780,-1780),Vector2(1780,1780))
|
||||
@ -207,7 +207,9 @@ func _input(event: InputEvent) -> void:
|
||||
_dialog.hide()
|
||||
else:
|
||||
_return(true)
|
||||
elif event.keycode == KEY_F and not _dialog.visible:
|
||||
elif event.keycode == KEY_E and _dialog.visible and not _poi.is_empty() and _poi.kind in preload("res://scripts/planets/poi_rules.gd").KINDS and _poi.complete:
|
||||
_dialog.hide()
|
||||
elif event.keycode == KEY_E and not _dialog.visible:
|
||||
for encounter in world.data.events:
|
||||
if not encounter.complete and lander.position.distance_to(encounter.position) <= 180:
|
||||
_event_armed = false
|
||||
@ -224,6 +226,10 @@ func _input(event: InputEvent) -> void:
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func _show_poi(message := "") -> void:
|
||||
_active_event = {}
|
||||
if _poi.kind in preload("res://scripts/planets/poi_rules.gd").KINDS and not _poi.complete:
|
||||
_attempt()
|
||||
return
|
||||
for child in _choices.get_children():
|
||||
_choices.remove_child(child)
|
||||
child.queue_free()
|
||||
@ -240,24 +246,35 @@ func _show_poi(message := "") -> void:
|
||||
if _poi.kind in ["deep_deposit", "crew"]:
|
||||
_show_colony_poi(message)
|
||||
return
|
||||
var stage := clampi(int(_poi.stage),0,2)
|
||||
POI_CARD.header(_choices,str(_poi.kind),stage,bool(_poi.complete))
|
||||
if not message.is_empty():
|
||||
POI_CARD.text(_choices,message,13,POI_CARD.GOLD)
|
||||
var report := PROFILES.threat_report(progress.active_profile,captain)
|
||||
if not _poi.complete:
|
||||
var chance := PROFILES.success_chance(progress.active_profile,captain,_poi.stage)
|
||||
var stages: Dictionary = preload("res://scripts/planets/poi_rules.gd").STAGES
|
||||
POI_CARD.text(_choices,"DO ODZYSKANIA",11,POI_CARD.MUTED)
|
||||
POI_CARD.text(_choices,preload("res://scripts/planets/poi_rules.gd").PREVIEWS[_poi.kind][stage],14,POI_CARD.GOLD)
|
||||
POI_CARD.text(_choices,"Powodzenie %.1f%% · Zagrożenie %.1f%% / 300%%" % [chance*100,report.total],12,POI_CARD.MUTED)
|
||||
POI_CARD.text(_choices,"Porażka uszkadza lądownik i zamyka to miejsce. Łup zachowasz po powrocie.",12,POI_CARD.MUTED)
|
||||
var attempt := POI_CARD.button(_choices,str(stages[_poi.kind][stage]),_attempt,true)
|
||||
attempt.disabled = chance <= 0.0
|
||||
if attempt.disabled:
|
||||
attempt.tooltip_text = "Brak szans przy obecnym zagrożeniu. Potrzebujesz lepszego wyposażenia."
|
||||
POI_CARD.button(_choices,"Zakończ badanie tego miejsca",func(): _poi.complete = true; _dialog.hide())
|
||||
POI_CARD.button(_choices, "Wróć do wyprawy", func(): _dialog.hide())
|
||||
POI_CARD.header(_choices,str(_poi.kind),0,true)
|
||||
var result: Dictionary = _poi.get("loot_result",{})
|
||||
if result.is_empty():
|
||||
POI_CARD.text(_choices,"To miejsce zostało już odwiedzone.",14,POI_CARD.GOLD)
|
||||
else:
|
||||
POI_CARD.text(_choices,"ZDOBYTO",13,POI_CARD.GOLD)
|
||||
if not result.materials.is_empty(): POI_CARD.text(_choices,UI.material_text(result.materials),15)
|
||||
for item in result.modules:
|
||||
var row := HBoxContainer.new()
|
||||
row.name = "LootModuleRow"
|
||||
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_theme_constant_override("separation",10)
|
||||
_choices.add_child(row)
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = item.definition.icon
|
||||
icon.custom_minimum_size = Vector2(36,36)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
row.add_child(icon)
|
||||
var name_label := POI_CARD.text(row,"%s · poziom %d" % [item.definition.display_name,item.item_level],14,item.get_rarity_color())
|
||||
name_label.name = "LootModuleName"
|
||||
name_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
name_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
name_label.tooltip_text = item.get_tooltip_text()
|
||||
var loot: Dictionary = result.loot
|
||||
POI_CARD.text(_choices,"Łup ×%.2f · sprzęt ×%.2f · odzysk %.0f%%\nZagrożenie po ochronie: %.1f%% / 300%%" % [loot.multiplier,loot.gear_multiplier,loot.recovery*100.0,loot.threat],12,POI_CARD.MUTED)
|
||||
POI_CARD.text(_choices,"Znaleziska są w ładowni wyprawy. Zachowasz je po bezpiecznym powrocie na statek.",12,POI_CARD.MUTED)
|
||||
POI_CARD.button(_choices, "Kontynuuj wyprawę [E]", func(): _dialog.hide(),true)
|
||||
|
||||
func _attempt() -> void:
|
||||
if _ending:
|
||||
@ -265,20 +282,12 @@ func _attempt() -> void:
|
||||
var result: Dictionary = progress.resolve_poi(captain, _poi, _rng)
|
||||
if result.is_empty():
|
||||
return
|
||||
if result.get("blocked",false):
|
||||
_show_poi(str(result.reason))
|
||||
return
|
||||
var message := ""
|
||||
if result.success:
|
||||
message = "SUKCES · " + UI.material_text(result.materials)
|
||||
if result.module != null:
|
||||
message += "\nZnaleziono moduł statku, poziom %d." % result.module.item_level
|
||||
if _poi.complete:
|
||||
message += "\nMiejsce w pełni zbadane."
|
||||
else:
|
||||
message = "NIEPOWODZENIE · utrata %d HP.\nDalsze badanie tego miejsca jest niemożliwe." % result.damage
|
||||
var rarity := 0
|
||||
for item in result.modules: rarity = maxi(rarity,item.rarity)
|
||||
preload("res://scripts/items/loot_reveal_effect.gd").spawn(lander.get_parent(),lander.position,Color("f1cd86"),rarity,true)
|
||||
_update_hud()
|
||||
_show_poi(message)
|
||||
world.refresh_pois(lander.position)
|
||||
_show_poi()
|
||||
if progress.lander_hp <= 0:
|
||||
await _destroy_lander()
|
||||
|
||||
@ -300,7 +309,8 @@ func _update_hud() -> void:
|
||||
_hp.value = progress.lander_hp
|
||||
if not _ending:
|
||||
_status.text = "Lądownik %d / 100 HP · Energia %d%%" % [ceili(progress.lander_hp),roundi(_motion.energy)] + ("\nPogoda: " + weather.display_name() if is_instance_valid(weather) else "")
|
||||
_threat.text = "Ryzyko %.1f%% / 300%% · Śr. POI %.1f%%" % [PROFILES.global_threat(progress.active_profile,captain),PROFILES.average_success_chance(progress.active_profile,captain)*100.0]
|
||||
var loot_report := PROFILES.poi_loot_report(progress.active_profile,captain)
|
||||
_threat.text = "Zagrożenie %.1f%% / 300%% · Łup POI ×%.2f" % [loot_report.threat,loot_report.multiplier]
|
||||
var loot_data: Dictionary = progress.cargo.duplicate()
|
||||
if progress.cargo_parts > 0: loot_data.parts = progress.cargo_parts
|
||||
if progress.cargo_missiles > 0: loot_data.missile = progress.cargo_missiles
|
||||
@ -338,6 +348,7 @@ func _event_text(text: String, color := Color("d5e4e8"), font_size := 15) -> Lab
|
||||
return label
|
||||
|
||||
func _show_event(event: Dictionary, result: Dictionary = {}) -> void:
|
||||
_poi = {}
|
||||
_active_event = event
|
||||
EVENTS.prepare(event,captain,progress)
|
||||
for child in _choices.get_children():
|
||||
|
||||
@ -69,7 +69,7 @@ func _ready() -> void:
|
||||
sprite.set_script(preload("res://scripts/planets/surface_cave.gd"))
|
||||
sprite.configure(data,poi)
|
||||
else:
|
||||
var textures := {"ruins":"ruins", "warehouse":"props/warehouse", "village":"landmarks/abandoned_hamlet", "crew":"props/engineer_camp", "hermit":"props/hermit_cartographer", "time_engineer":"props/time_engineer"}
|
||||
var textures := {"ruins":"ruins", "warehouse":"props/warehouse", "village":"landmarks/abandoned_hamlet", "crew":"props/engineer_camp", "hermit":"props/hermit_cartographer_grounded", "time_engineer":"props/time_engineer_grounded"}
|
||||
sprite.texture = load("res://assets/planets/%s.png" % textures[poi.kind])
|
||||
sprite.position = poi.position
|
||||
if sprite.texture != null and poi.kind != "cave":
|
||||
@ -78,6 +78,19 @@ func _ready() -> void:
|
||||
if poi.kind == "crew" and sprite.texture != null:
|
||||
sprite.scale = Vector2.ONE * 170.0 / maxf(sprite.texture.get_width(),sprite.texture.get_height())
|
||||
add_child(sprite)
|
||||
if poi.kind in ["hermit","time_engineer"]:
|
||||
var grounding := ShaderMaterial.new()
|
||||
grounding.shader = preload("res://resources/effects/hermit_grounding.gdshader")
|
||||
var soil: Color = (data.landscape.low as Color).lerp(data.landscape.high,0.35)
|
||||
grounding.set_shader_parameter("ground_tint",soil)
|
||||
sprite.material = grounding
|
||||
var contact := Node2D.new()
|
||||
contact.name = "GroundContact"
|
||||
contact.set_script(preload("res://scripts/planets/hermit_ground_contact.gd"))
|
||||
contact.soil = soil.darkened(0.2)
|
||||
contact.scale = Vector2.ONE/sprite.scale.x
|
||||
contact.show_behind_parent = true
|
||||
sprite.add_child(contact)
|
||||
_poi_sprites[poi.id] = sprite
|
||||
var label := Label.new()
|
||||
label.position = poi.position + Vector2(-120, 46)
|
||||
@ -153,22 +166,22 @@ func refresh_pois(lander_position: Vector2) -> void:
|
||||
var network := preload("res://scripts/planets/mining_network.gd")
|
||||
var richness: int = network.station_richness(GameState.captain.expedition.mining_stations[str(data.profile.id)]) if built else network.deposit_richness(data.profile, int(data.profile.get("system_level", GameState.system_level)))
|
||||
label.text = ("%s · %d/100" % ["Placówka górnicza" if built else "Głębokie złoże deuteru", richness])
|
||||
if lander_position.distance_to(poi.position) <= 150: label.text += "\n[F] Placówka" if built else "\n[F] Buduj"
|
||||
if lander_position.distance_to(poi.position) <= 150: label.text += "\n[E] Placówka" if built else "\n[E] Buduj"
|
||||
continue
|
||||
if poi.kind == "time_engineer":
|
||||
label.text = "Inżynier chronalny" + ("\n[F] Maksymalizuj addon" if lander_position.distance_to(poi.position) <= 150 else "")
|
||||
label.text = "Inżynier chronalny" + ("\n[E] Maksymalizuj addon" if lander_position.distance_to(poi.position) <= 150 else "")
|
||||
continue
|
||||
if poi.kind == "hermit":
|
||||
var progress: Resource = GameState.captain.expedition
|
||||
var map := preload("res://scripts/planets/distant_expeditions.gd").visit_offer(progress, data.profile, int(data.profile.get("system_level", GameState.system_level)))
|
||||
var owned: bool = progress.hermit_purchases.has(str(map.id))
|
||||
label.text = "Pustelnik / Kartograf" + (" · mapa kupiona" if owned else ("\n[F] Kup mapę" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
label.text = "Pustelnik / Kartograf" + (" · mapa kupiona" if owned else ("\n[E] Kup mapę" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
continue
|
||||
if poi.kind == "crew":
|
||||
label.text = "Obóz specjalisty" + (" · zatrudniono" if poi.complete else ("\n[F] Porozmawiaj" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
label.text = "Obóz specjalisty" + (" · zatrudniono" if poi.complete else ("\n[E] Porozmawiaj" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
continue
|
||||
var title: String = preload("res://scripts/planets/poi_rules.gd").NAMES[poi.kind]
|
||||
label.text = title + ((" · zatrudniono" if poi.kind == "crew" else " · zbadano") if poi.complete else ("\n[F] Zbadaj" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
label.text = title + (" · odwiedzono" if poi.complete else ("\n[E] Zbierz znaleziska" if lander_position.distance_to(poi.position) <= 150 else ""))
|
||||
|
||||
func _draw() -> void:
|
||||
if terrain == null:
|
||||
|
||||
@ -173,15 +173,48 @@ func _build_loadout() -> void:
|
||||
picker.item_selected.connect(func(index: int) -> void: _captain.equip_skill(slot, str(picker.get_item_metadata(index))))
|
||||
column.add_child(picker)
|
||||
|
||||
func _icon(skill: String, dimensions: float) -> TextureRect:
|
||||
func _icon(skill: String, dimensions: float) -> PanelContainer:
|
||||
var accent := Color(CATALOG.DATA[skill]["color"])
|
||||
var frame := PanelContainer.new()
|
||||
frame.name = "SkillIconFrame"
|
||||
frame.custom_minimum_size = Vector2.ONE * dimensions
|
||||
frame.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
frame.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
frame.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
var metal := StyleBoxFlat.new()
|
||||
metal.bg_color = Color("111f30")
|
||||
metal.border_color = accent.darkened(0.25)
|
||||
metal.set_border_width_all(2)
|
||||
metal.border_width_bottom = 3
|
||||
metal.set_corner_radius_all(10 if dimensions > 50 else 7)
|
||||
metal.set_content_margin_all(5 if dimensions > 50 else 3)
|
||||
metal.shadow_color = Color(0,0,0,0.55)
|
||||
metal.shadow_size = 5
|
||||
metal.shadow_offset = Vector2(0,3)
|
||||
frame.add_theme_stylebox_override("panel",metal)
|
||||
var inset := PanelContainer.new()
|
||||
inset.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
var rim := StyleBoxFlat.new()
|
||||
rim.bg_color = Color("07101b")
|
||||
rim.border_color = Color(accent.lightened(0.3),0.6)
|
||||
rim.set_border_width_all(1)
|
||||
rim.set_corner_radius_all(6)
|
||||
rim.set_content_margin_all(2)
|
||||
inset.add_theme_stylebox_override("panel",rim)
|
||||
frame.add_child(inset)
|
||||
var icon := TextureRect.new()
|
||||
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
||||
icon.texture = CATALOG.icon(skill)
|
||||
icon.custom_minimum_size = Vector2.ONE * dimensions
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
|
||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
return icon
|
||||
var material := ShaderMaterial.new()
|
||||
material.shader = preload("res://resources/ui/skill_icon.gdshader")
|
||||
material.set_shader_parameter("corner_radius",5.0)
|
||||
icon.material = material
|
||||
icon.resized.connect(func(): material.set_shader_parameter("icon_size",icon.size))
|
||||
inset.add_child(icon)
|
||||
return frame
|
||||
|
||||
func _choice_card(skill: String) -> PanelContainer:
|
||||
var rank := _captain.get_skill_rank(skill)
|
||||
@ -197,7 +230,7 @@ func _choice_card(skill: String) -> PanelContainer:
|
||||
body.add_theme_constant_override("separation", 6)
|
||||
card.add_child(body)
|
||||
body.add_child(_label("NOWA UMIEJĘTNOŚĆ" if rank == 0 else "ULEPSZENIE %s → %s" % [str(rank), str(next_rank)], 11, color))
|
||||
body.add_child(_icon(skill, 54))
|
||||
body.add_child(_icon(skill, 76))
|
||||
var title := _label(data["name"], 19)
|
||||
title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
body.add_child(title)
|
||||
|
||||
@ -8,7 +8,7 @@ const PAGES := [
|
||||
["Walka i przetrwanie", "03", "[font_size=16][color=#f1bd79]Wróć z wyprawy[/color][/font_size]\n\n[color=#91dbea][b]Tarcze, kadłub i energia[/b][/color]\nTarcze pochłaniają obrażenia przed kadłubem. Utrata całego kadłuba oznacza zniszczenie statku. Energia zasila część broni oraz dopalanie; odnawia się z czasem, szybciej przy gwieździe.\n\n[color=#91dbea][b]Dobieraj broń do zapasów[/b][/color]\nBroń energetyczna zużywa energię. Działko maszynowe potrzebuje zwykłej amunicji, gamma — napromieniowanej, a wyrzutnie — rakiet. Puste zapasy oznaczają brak strzału. Absorpcja ogranicza obrażenia danego typu.\n\n[color=#91dbea][b]Korzystaj z rozszerzeń[/b][/color]\nMiny atakują obszarowo, flary odciągają uwagę, kamuflaż pomaga zerwać kontakt, teleport przenosi w bezpieczne miejsce, a drony wspierają ostrzał. Doładowanie tarcz działa przy gwieździe. Sprawdzaj koszt i cooldown w opisie.\n\n[color=#f1bd79][b]Uważaj na uciekających przeciwników[/b][/color]\nWróg z kadłubem poniżej 10% ucieka wolniej, ale może zostawić minę. Nie leć bezmyślnie prosto za nim."],
|
||||
["Łup i wytwarzanie", "04", "[font_size=16][color=#f1bd79]Zbieraj. Porównuj. Twórz.[/color][/font_size]\n\n[color=#91dbea][b]Łup zbierasz przez podlecenie[/b][/color]\nPrzedmioty w pobliżu są przyciągane do statku. Magazyn mieści 20 przedmiotów; przy pełnym magazynie zwolnij miejsce, żeby zebrać kolejny.\n\n[color=#91dbea][b]Asteroidy zostawiają fizyczne odłamki[/b][/color]\nStrzelaj do asteroid. Po zniszczeniu rozpadają się bazowo na 5–7 poszarpanych fragmentów. Każdy to jedna jednostka surowca — musisz go zebrać. Umiejętność górnika zwiększa uzysk.\n\n[color=#91dbea][b]Przeszukuj wraki[/b][/color]\nPodleć do wraku i przytrzymaj E, aby go przeszukać. Wraki dają surowce (65%), amunicję lub rakiety (łącznie 20%) albo moduł (15%).\n\n[color=#91dbea][b]Warsztat fregaty — produkcja[/b][/color]\nZadokuj na fregacie i wybierz Warsztat. Tam wytworzysz amunicję, rakiety, części, powerbanki i wyposażenie kapitana. Koszt sprawdzisz w podpowiedzi przycisku produkcji.\n\n[color=#91dbea][b]Odzyskuj części[/b][/color]\nNajedź na zbędny przedmiot w magazynie i użyj przycisku rozłożenia. Części przydadzą się do napraw."],
|
||||
["Statek i kapitan", "05", "[font_size=16][color=#f1bd79]Buduj własny styl gry[/color][/font_size]\n\n[color=#91dbea][b]Wyposażenie[/b][/color]\nKliknij panel statku w prawym górnym rogu i otwórz magazyn. Przeciągaj przedmioty do pasujących slotów: maksymalnie 3 bronie, 5 modułów i 5 rozszerzeń. Na początku dostępny jest 1 slot broni i 1 rozszerzenia. Pierwszy dodatkowy slot broni kosztuje 100 tytanu, drugi 500. Rozszerzenia kosztują po 40 żelaza, aluminium i tytanu, a każdy kolejny slot podwaja ten koszt (80, 160, 320). Ładownia zaczyna z 5 miejscami; każde kolejne miejsce kosztuje 100 żelaza i 50 aluminium. Sloty odblokowujesz w hangarze fregaty. Po zbudowaniu składu modułów zakładka Magazyn na frachtowcu pozwala odkładać i odbierać wyposażenie. Aktywne rozszerzenia uruchamiasz klawiszami 1–5; pasywne (oznaczone P) działają automatycznie w tych samych slotach. Najedź kursorem, żeby sprawdzić parametry i porównanie wyposażenia.\n\n[color=#91dbea][b]Nie każdy duplikat jest taki sam[/b][/color]\nBroń i moduły mogą mieć różne parametry oraz addony. Aktywne rozszerzenia losują cooldown od 30 do 5 pełnych sekund. Pasywne mają losowaną siłę efektu: Recykler odnawia tarcze i energię po zebraniu odłamka, Wirus przejmuje uciekających wrogów, a Pancerz z tytanu ogranicza obrażenia przy niskim kadłubie. Krótsze odnowienia są rzadkie — przed rozłożeniem porównaj egzemplarze. Rozszerzenia tego samego typu dzielą aktywne odnowienie.\n\n[color=#91dbea][b]Umiejętności kapitana[/b][/color]\nZa pokonanych wrogów zdobywasz doświadczenie i kredyty. Trudniejsze układy dają więcej bazowego XP. Jeśli kapitan przewyższa poziom układu o ponad 2 poziomy, XP za przeciwników i ruiny maleje; przy przewadze 8 poziomów spada do zera. Kredyty i surowce nadal zbierasz. Po awansie wybierasz umiejętność. Pasywne działają stale, aktywne przypisujesz do F1–F5.\n\n[color=#f1bd79][b]Okno umiejętności nie pauzuje gry.[/b][/color]\nOtwieraj je w bezpiecznym miejscu. Przed kolejnym układem uzupełnij zapasy i sprawdź wyposażenie."]
|
||||
,["Planety i frachtowiec", "06", "[font_size=16][color=#f1bd79]Wyprawa na powierzchnię[/color][/font_size]\n\nPodleć do planety oznaczonej EARTHLIKE. [b]F[/b] skanuje tlen, temperaturę i zagrożenie biologiczne. [b]L[/b] rozpoczyna lądowanie. Możesz eksplorować przed pokonaniem wrogów, ale lądowanie jest zablokowane podczas walki.\n\nLądownik wymaga 100 HP przed startem i traci 5–20 HP przy wejściu w atmosferę. Na powierzchni sterujesz jak statkiem: [b]W[/b] — ciąg, [b]S[/b] — hamowanie i wstecz, [b]A/D[/b] — obrót, [b]Q/E[/b] — ruch boczny, [b]TAB[/b] — dopalanie. Odkrywaj miejsca i używaj [b]F[/b], aby je zbadać. Lądownik ma osobną energię dopalania. Każdy etap badania pokazuje szansę sukcesu; dalsze etapy dają więcej łupu i większe ryzyko.\n\n[b]L[/b] lub przycisk powrotu kończy wyprawę i przenosi łup do Twoich zasobów. Zniszczenie lądownika oznacza utratę tylko zdobyczy tej wyprawy. Kolejne lądowanie tworzy nową mapę.\n\n[color=#91dbea][b]Frachtowiec[/b][/color]\nZnajdziesz go przy gwieździe centralnej. Podleć i naciśnij [b]L[/b]. Hangar naprawia lądownik (1 część za 1% HP), warsztat prowadzi całą produkcję amunicji, rakiet, zaopatrzenia i sprzętu kapitana, a laboratorium przechowuje skany i archiwa.\n\nKapitan zaczyna z podstawowym systemem oddychania, skafandrem i bronią ręczną. Kolejne poziomy tworzysz w warsztacie; posiadany sprzęt zmienisz w Warsztacie. Kliknięcie panelu kapitana pokazuje sylwetkę, założone przedmioty i redukcję zagrożeń nad slotami. Wyższy poziom poprawia szanse eksploracji.\n\n[color=#91dbea][b]Losowe spotkania[/b][/color]\nPytajnik na mapie oznacza wydarzenie. Podleć, aby otworzyć okno. Miejscowy inżynier może zaoferować nieznany moduł za 100 kredytów. Wyższe poziomy przedmiotów są coraz rzadsze. Kupiony moduł pozostaje w ładowni wyprawy do bezpiecznego powrotu.\n\n[color=#f1bd79]Podczas wyprawy i wizyty we frachtowcu kosmos jest zamrożony. Zapisywanie między uruchomieniami gry nie jest jeszcze dostępne.[/color]"]
|
||||
,["Planety i frachtowiec", "06", "[font_size=16][color=#f1bd79]Wyprawa na powierzchnię[/color][/font_size]\n\nPodleć do planety oznaczonej EARTHLIKE. [b]F[/b] skanuje tlen, temperaturę i zagrożenie biologiczne. [b]L[/b] rozpoczyna lądowanie. Możesz eksplorować przed pokonaniem wrogów, ale lądowanie jest zablokowane podczas walki.\n\nLądownik wymaga 100 HP przed startem i traci 5–20 HP przy wejściu w atmosferę. Na powierzchni sterujesz jak statkiem: [b]W[/b] — ciąg, [b]S[/b] — hamowanie i wstecz, [b]A/D[/b] — obrót, [b]Q/R[/b] — ruch boczny, [b]TAB[/b] — dopalanie. Podleć do zwykłego POI i naciśnij [b]E[/b], aby od razu zobaczyć zdobyte znaleziska. Lądownik ma osobną energię dopalania. Ilość łupu zwiększa wyposażenie kapitana, a zmniejszają zagrożenia, przed którymi nie chroni sprzęt. Wydarzenia oznaczone pytajnikiem oraz usługi inżynierów i kartografów zachowują osobne okna.\n\n[b]L[/b] lub przycisk powrotu kończy wyprawę i przenosi łup do Twoich zasobów. Zniszczenie lądownika oznacza utratę tylko zdobyczy tej wyprawy. Kolejne lądowanie tworzy nową mapę.\n\n[color=#91dbea][b]Frachtowiec[/b][/color]\nZnajdziesz go przy gwieździe centralnej. Podleć i naciśnij [b]L[/b]. Hangar naprawia lądownik (1 część za 1% HP), warsztat prowadzi całą produkcję amunicji, rakiet, zaopatrzenia i sprzętu kapitana, a laboratorium przechowuje skany i archiwa.\n\nKapitan zaczyna z podstawowym systemem oddychania, skafandrem i bronią ręczną. Kolejne poziomy tworzysz w warsztacie; posiadany sprzęt zmienisz w Warsztacie. Kliknięcie panelu kapitana pokazuje sylwetkę, założone przedmioty i redukcję zagrożeń nad slotami. Lepszy sprzęt zwiększa ilość łupu z POI i ogranicza ryzyko specjalnych wydarzeń.\n\n[color=#91dbea][b]Losowe spotkania[/b][/color]\nPytajnik na mapie oznacza wydarzenie. Podleć, aby otworzyć okno. Miejscowy inżynier może zaoferować nieznany moduł za 100 kredytów. Wyższe poziomy przedmiotów są coraz rzadsze. Kupiony moduł pozostaje w ładowni wyprawy do bezpiecznego powrotu.\n\n[color=#f1bd79]Podczas wyprawy i wizyty we frachtowcu kosmos jest zamrożony. Zapisywanie między uruchomieniami gry nie jest jeszcze dostępne.[/color]"]
|
||||
, ["Autorzy dźwięków", "07", "[font_size=16][color=#f1bd79]Dźwięki otoczenia[/color][/font_size]\n\n[b]Blender Foundation — Ambient Bird, Cricket and Frog (Yo Frankie!)[/b]\nOdgłosy świerszcza i żaby, udostępnione przez Lamoot:\nhttps://opengameart.org/content/ambient-bird-cricket-and-frog\nLicencja Creative Commons Attribution 3.0:\nhttps://creativecommons.org/licenses/by/3.0/\nZmiany: filtrowanie, płynne początki i zakończenia, zmiana wysokości żaby oraz konwersja do stereo 48 kHz. Autorzy nie są powiązani z tą grą.\n\n[b]Nagrania na licencji CC0[/b]\nThimras — Park ambiences (wiatr).\nIwan „qubodup” Gabovitch — 20 Rustles of dry leaves.\nisaiah658 — Ambient Bird Sounds.\nRudmer_Rotteveel — Wood Creak Single V7.\n\n[b]Wnętrze fregaty — CC0[/b]\nLEGIT Audio — The Shop (bezpłatne próbki OpenGameArt).\nbart — 68 Workshop Sounds i Steam release sounds.\nKenney — Sci-Fi Sounds.\n\nSzczegółowe źródła i zakres obróbki znajdują się w plikach CREDITS.md i manifest.json przy zasobach audio."]
|
||||
]
|
||||
var _panel: PanelContainer
|
||||
|
||||
@ -246,6 +246,8 @@ func _equipment() -> void:
|
||||
else:
|
||||
_item_header(card,item)
|
||||
UI.label(card,"%s: %.1f %s" % [ItemInstance.stat_name(item.definition.primary_stat), item.get_stat_total(item.definition.primary_stat),item.definition.stat_suffix],12,UI.MUTED)
|
||||
if item.definition.shield_regeneration_bonus > 0.0:
|
||||
UI.label(card,"Regeneracja tarcz: +%.1f pkt/s" % item.get_base_shield_regeneration(),12,UI.MUTED)
|
||||
card = _section("ROZSZERZENIA", ENERGY)
|
||||
for index in range(inventory.EXTENSION_SLOT_COUNT):
|
||||
UI.label(card,"SLOT %d" % (index+1),12,ENERGY)
|
||||
|
||||
57
tests/items/enemy_shield_damage_audit.gd
Normal file
@ -0,0 +1,57 @@
|
||||
extends Node2D
|
||||
|
||||
const ENEMY := preload("res://scenes/game/enemy_ship.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
var enemy := ENEMY.instantiate()
|
||||
add_child(enemy)
|
||||
enemy.set_physics_process(false)
|
||||
enemy.absorption = Vector3.ZERO
|
||||
enemy.max_hull = 125.0
|
||||
enemy.hull = 125.0
|
||||
enemy.max_shields = 50.0
|
||||
enemy.shields = 50.0
|
||||
# Four hits consume the shield; none of that absorbed damage reaches hull.
|
||||
for hit in 4:
|
||||
enemy.take_research_weapon_hit(12.5,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(is_equal_approx(enemy.hull,125.0))
|
||||
assert(enemy.shields == 0.0 and not enemy.is_queued_for_deletion())
|
||||
# Regeneration immediately restores a fraction of a point, making the ring visible again.
|
||||
enemy.regenerate_defenses(0.1)
|
||||
assert(is_equal_approx(enemy.shields,0.05))
|
||||
enemy.take_research_weapon_hit(12.5,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(is_equal_approx(enemy.hull,112.55))
|
||||
# Overflow applies only the unabsorbed portion, including research multipliers.
|
||||
enemy.hull = 125.0
|
||||
enemy.shields = 5.0
|
||||
enemy.take_research_weapon_hit(15.0,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(enemy.shields == 0.0 and is_equal_approx(enemy.hull,115.0))
|
||||
GameState.captain.expedition.alien_skills = {"shields":true,"hull":true}
|
||||
enemy.hull = 125.0
|
||||
enemy.shields = 11.0
|
||||
enemy.take_research_weapon_hit(20.0,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(is_equal_approx(enemy.hull,114.0))
|
||||
GameState.captain.expedition.alien_skills.clear()
|
||||
# A projectile hitting both shield interception and hull can only damage once.
|
||||
enemy.hull = 125.0
|
||||
enemy.shields = 0.0
|
||||
var projectile := preload("res://scenes/game/weapon_projectile.tscn").instantiate()
|
||||
projectile.configure(Vector2.ZERO,Vector2.RIGHT,ItemDefinition.WeaponKind.PLASMA,500,12.5,500)
|
||||
add_child(projectile)
|
||||
projectile.set_physics_process(false)
|
||||
projectile._apply_damage_once(enemy)
|
||||
projectile._apply_damage_once(enemy)
|
||||
assert(is_equal_approx(enemy.hull,112.5))
|
||||
# Full hull takes ten additional 12.5-damage hits after an exactly depleted shield.
|
||||
enemy.hull = 125.0
|
||||
enemy.shields = 0.0
|
||||
for hit in 9:
|
||||
enemy.take_research_weapon_hit(12.5,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(enemy.hull > 0.0 and not enemy.is_queued_for_deletion())
|
||||
assert(is_equal_approx(enemy.hull,12.5))
|
||||
enemy.take_research_weapon_hit(12.5,false,DamageTypes.Type.ENERGY,0.0,-1)
|
||||
assert(enemy.hull == 0.0 and enemy.is_queued_for_deletion())
|
||||
print("ENEMY SHIELD DAMAGE AUDIT PASS: no hull damage under full absorption, exact shield break survives, correct overflow/research scaling, no duplicate projectile damage, 10 hull hits after shield break; instant 0.05 shield regeneration confirmed")
|
||||
await get_tree().process_frame
|
||||
get_tree().quit()
|
||||
1
tests/items/enemy_shield_damage_audit.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bpuveichg42sd
|
||||
4
tests/items/enemy_shield_damage_audit.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/items/enemy_shield_damage_audit.gd" id="1"]
|
||||
[node name="EnemyShieldDamageAudit" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
51
tests/items/shield_module_regeneration_test.gd
Normal file
@ -0,0 +1,51 @@
|
||||
extends Node
|
||||
|
||||
const GENERATOR := preload("res://scripts/items/item_generator.gd")
|
||||
const BALANCE := preload("res://scripts/levels/level_balance.gd")
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
for definition in [preload("res://resources/items/reinforced_shield.tres"),preload("res://resources/items/shield_recharger.tres")]:
|
||||
var legacy := ItemInstance.new()
|
||||
legacy.definition = definition
|
||||
assert(legacy.get_stat_total("max_shields") == definition.primary_value)
|
||||
assert(legacy.get_stat_total("shield_regeneration") == 2.0)
|
||||
legacy.item_level = 50
|
||||
assert(is_equal_approx(legacy.get_base_shield_regeneration(),2.0*BALANCE.item_stat_scale(50)))
|
||||
for level in [1,10,50,120]:
|
||||
for roll in 20:
|
||||
var item := GENERATOR.generate_for_definition(definition,level)
|
||||
var expected := 2.0*BALANCE.item_stat_scale(level)
|
||||
assert(item.get_base_shield_regeneration() >= expected*0.8-0.001)
|
||||
assert(item.get_base_shield_regeneration() <= expected*1.2+0.001)
|
||||
assert(item.get_tooltip_text().contains("Regeneracja tarcz:"))
|
||||
var addon := ItemStatModifier.new()
|
||||
addon.stat_key = "shield_regeneration"
|
||||
addon.value = 1.25
|
||||
legacy.additional_modifiers.append(addon)
|
||||
assert(is_equal_approx(legacy.get_stat_total("shield_regeneration"),legacy.get_base_shield_regeneration()+1.25))
|
||||
assert(GENERATOR.advance(legacy))
|
||||
assert(legacy.item_level == 51 and legacy.shield_regeneration_override > 0.0)
|
||||
assert(ResourceSaver.save(legacy,"res://tmp/shield_regen_roundtrip.tres") == OK)
|
||||
var restored := ResourceLoader.load("res://tmp/shield_regen_roundtrip.tres","",ResourceLoader.CACHE_MODE_IGNORE) as ItemInstance
|
||||
assert(is_equal_approx(restored.get_stat_total("shield_regeneration"),legacy.get_stat_total("shield_regeneration")))
|
||||
DirAccess.remove_absolute(ProjectSettings.globalize_path("res://tmp/shield_regen_roundtrip.tres"))
|
||||
var game := preload("res://scenes/game/game.tscn").instantiate()
|
||||
add_child(game)
|
||||
await get_tree().process_frame
|
||||
var ship := game.get_node("PlayerShip")
|
||||
ship.set_physics_process(false)
|
||||
var inventory: ShipInventory = ship.get_node("ShipInventory")
|
||||
var item := ItemInstance.new()
|
||||
item.definition = preload("res://resources/items/reinforced_shield.tres")
|
||||
assert(inventory.add_item(item))
|
||||
assert(inventory.move_item("cargo",inventory.cargo.find(item),"module",0))
|
||||
assert(is_equal_approx(ship.max_shields,ship.base_max_shields+30.0))
|
||||
assert(is_equal_approx(ship.shield_regeneration,2.0))
|
||||
ship.shields = 0.0
|
||||
ship._physics_process(0.5)
|
||||
assert(is_equal_approx(ship.shields,1.0))
|
||||
print("SHIELD MODULE REGENERATION PASS: both definitions, legacy items, level scaling, affixes, upgrade, persistence, equipped capacity and actual regeneration")
|
||||
game.queue_free()
|
||||
await get_tree().process_frame
|
||||
get_tree().quit()
|
||||
1
tests/items/shield_module_regeneration_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://djqy5y0d6h7s2
|
||||
4
tests/items/shield_module_regeneration_test.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/items/shield_module_regeneration_test.gd" id="1"]
|
||||
[node name="ShieldModuleRegenerationTest" type="Node"]
|
||||
script = ExtResource("1")
|
||||
@ -51,8 +51,8 @@ func _ready() -> void:
|
||||
game.player.angular_velocity = 0
|
||||
game.player.position = game.protected_planet.position
|
||||
manager._process(0)
|
||||
assert(manager._text.text.contains("TLEN") and manager._text.text.contains("TEMPERATURA") and manager._text.text.contains("FLORA"))
|
||||
assert(manager._text.text.contains("Pierwszy etap POI"))
|
||||
assert(manager._text.text.contains("TLEN") and manager._text.text.contains("TEMP") and manager._text.text.contains("BIO"))
|
||||
assert(manager._text.text.contains("ŁUP POI"))
|
||||
manager.land_nearby()
|
||||
var screen: Control = manager.screen
|
||||
assert(screen._motion.max_speed == game.player.max_speed)
|
||||
@ -60,10 +60,10 @@ func _ready() -> void:
|
||||
screen.lander.position = screen.world.data.pois[0].position
|
||||
var key := InputEventKey.new()
|
||||
key.pressed = true
|
||||
key.keycode = KEY_E
|
||||
key.keycode = KEY_F
|
||||
screen._input(key)
|
||||
assert(not screen._dialog.visible)
|
||||
key.keycode = KEY_F
|
||||
key.keycode = KEY_E
|
||||
screen._input(key)
|
||||
assert(screen._dialog.visible)
|
||||
var ship_energy: float = game.player.energy
|
||||
@ -76,5 +76,5 @@ func _ready() -> void:
|
||||
manager.finish_surface(true)
|
||||
game.queue_free()
|
||||
await get_tree().process_frame
|
||||
print("LANDER FLIGHT PASS: thrust, inertia, brake/reverse, rotation, local strafe, boost, shared parameters, F interaction, immediate scan")
|
||||
print("LANDER FLIGHT PASS: thrust, inertia, brake/reverse, rotation, local strafe, boost, shared parameters, E interaction, immediate scan")
|
||||
get_tree().quit()
|
||||
|
||||
@ -65,24 +65,24 @@ func _ready() -> void:
|
||||
chest_rng.seed = seed_value
|
||||
var prize := EVENTS._mystery(chest_rng,32,profile)
|
||||
hidden.append(prize)
|
||||
# Deposits scale rare materials; structures grant exact stage levels.
|
||||
# One visit grants loot; gear and effective hazards scale its quantity.
|
||||
var modules := 0
|
||||
for attempt in 1200:
|
||||
state.lander_hp = 100
|
||||
var stage := attempt%3
|
||||
var poi := {"kind":"deposit","stage":stage,"complete":false}
|
||||
var poi := {"kind":"deposit","complete":false}
|
||||
var result: Dictionary = state.resolve_poi(captain,poi,rng)
|
||||
if result.success:
|
||||
for key in result.materials:
|
||||
var minimum := roundi(5*(1+index)*(1.0+stage*0.65))
|
||||
var maximum := roundi(12*(1+index)*(1.0+stage*0.65))
|
||||
var yield_factor: float = PROFILES.poi_loot_report(profile,captain).multiplier
|
||||
var minimum := maxi(1,roundi(18*(1+index)*yield_factor))
|
||||
var maximum := maxi(1,roundi(28*(1+index)*yield_factor))
|
||||
assert(int(result.materials[key]) >= minimum and int(result.materials[key]) <= maximum)
|
||||
assert(result.module == null)
|
||||
var structure := {"kind":"ruins","stage":stage,"complete":false}
|
||||
var structure := {"kind":"ruins","complete":false}
|
||||
var structure_result: Dictionary = state.resolve_poi(captain,structure,rng)
|
||||
if structure_result.module != null:
|
||||
modules += 1
|
||||
assert(structure_result.module.item_level == 32+stage+1)
|
||||
assert(structure.complete and structure_result.module.item_level >= 32 and structure_result.module.item_level <= 44)
|
||||
state.cargo_modules.clear()
|
||||
assert(modules > 5)
|
||||
samples.append({"profile":profile,"missile_count":missiles.reward.missile,"missile_price":missiles.cost.credits,"ammo_barter_cost":barter_missiles.cost.iron,"goods_cost":goods.cost.credits,"hidden":hidden})
|
||||
|
||||
@ -84,8 +84,8 @@ func _ready() -> void:
|
||||
var rng_before := rng.state
|
||||
var poi := {"kind":"ruins","stage":2,"complete":false}
|
||||
var result: Dictionary = state.resolve_poi(captain,poi,rng)
|
||||
assert(result.blocked and result.chance == 0 and not poi.complete)
|
||||
assert(state.lander_hp == 100 and rng.state == rng_before)
|
||||
assert(result.success and poi.complete and result.modules.size() == 1)
|
||||
assert(state.lander_hp == 100 and rng.state != rng_before)
|
||||
var evacuation := {"kind":"evacuation","seed":1234,"complete":false}
|
||||
EVENTS.prepare(evacuation,captain,state)
|
||||
evacuation.stage = 2
|
||||
@ -99,7 +99,7 @@ func _ready() -> void:
|
||||
assert(is_equal_approx(EVENTS.chance(evacuation,captain,state),0.40))
|
||||
assert(is_equal_approx(EVENTS.chance({"kind":"rescue"},captain,state),0.90))
|
||||
var scan := PROFILES.scan_description(extreme,captain)
|
||||
assert(scan.contains("ŚREDNIA SZANSA POI: 66.7%") and scan.contains("90.0% / 70.0% / 40.0%"))
|
||||
assert(scan.contains("ŁUP POI: ×2.00") and not scan.contains("Etapy POI"))
|
||||
assert(scan.contains("Bez sprzętu: 300.0%"))
|
||||
for index in 1000:
|
||||
var generated := PROFILES.generate(99,index,"Biom")
|
||||
|
||||
@ -1,69 +1,84 @@
|
||||
extends Node
|
||||
const RULES := preload("res://scripts/planets/poi_rules.gd")
|
||||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||||
const CAPTAIN := preload("res://scripts/captain/captain_progress.gd")
|
||||
const GEAR := preload("res://scripts/planets/captain_equipment.gd")
|
||||
|
||||
func set_gear(captain: Resource, rank: int) -> void:
|
||||
for item in captain.gear_items: item.level = rank
|
||||
|
||||
func _ready() -> void:
|
||||
var captain := CAPTAIN.new()
|
||||
var state: Resource = captain.expedition
|
||||
var profile := {"id":"test","name":"Test","seed":42,"difficulty":0.0,"landing_damage":0,"oxygen":98,"temperature":30,"flora":0}
|
||||
var profile := {"id":"test","name":"Test","seed":42,"difficulty":0.0,"landing_damage":0,"oxygen":98,"temperature":30,"flora":0,"easy":true}
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = 42
|
||||
GameState.system_level = 20
|
||||
assert(state.begin_visit(profile))
|
||||
var samples_before := 0
|
||||
for kind in RULES.STAGES:
|
||||
for stage in 3:
|
||||
var success := false
|
||||
for attempt in 100:
|
||||
state.lander_hp = 100
|
||||
var poi := {"kind":kind,"stage":stage,"complete":false}
|
||||
for kind in RULES.KINDS:
|
||||
var poi := {"kind":kind,"complete":false}
|
||||
var hp: float = state.lander_hp
|
||||
var result: Dictionary = state.resolve_poi(captain,poi,rng)
|
||||
if not result.success: continue
|
||||
success = true
|
||||
assert(poi.stage == stage+1 and poi.complete == (stage==2))
|
||||
assert(result.success and result.damage == 0 and poi.complete)
|
||||
assert(state.lander_hp == hp)
|
||||
assert(poi.loot_result == result)
|
||||
var snapshot: Dictionary = state.cargo.duplicate()
|
||||
var module_count: int = state.cargo_modules.size()
|
||||
var rng_state := rng.state
|
||||
assert(state.resolve_poi(captain,poi,rng).is_empty())
|
||||
assert(state.cargo == snapshot and state.cargo_modules.size() == module_count and rng.state == rng_state)
|
||||
if kind == "ruins":
|
||||
assert(result.module.item_level == 21+stage and result.materials.is_empty())
|
||||
else: assert(result.module == null)
|
||||
if kind == "deposit":
|
||||
for key in result.materials: assert(key in ["silicon","copper","nickel","tungsten","mercury"])
|
||||
if kind == "cave":
|
||||
assert(result.materials == {"samples":[1,2,4][stage]})
|
||||
samples_before += [1,2,4][stage]
|
||||
if kind == "village" and stage == 1:
|
||||
assert(result.materials.experience == ceili(captain.get_xp_required()*0.1))
|
||||
if stage == 2: assert(state.resolve_poi(captain,poi,rng).is_empty())
|
||||
break
|
||||
assert(success)
|
||||
assert(result.modules.size() >= 1 and result.module == result.modules[0])
|
||||
for item in result.modules: assert(item.item_level >= 20 and item.item_level <= 24)
|
||||
else:
|
||||
assert(not result.materials.is_empty() and result.modules.is_empty())
|
||||
for amount in result.materials.values(): assert(int(amount) > 0)
|
||||
var samples := int(state.cargo.samples)
|
||||
var ammo := int(state.cargo.ammunition)
|
||||
var xp := int(state.cargo.experience)
|
||||
var credits := int(state.cargo.credits)
|
||||
assert(state.analysis_samples == 0 and captain.credits == 0)
|
||||
assert(captain.credits == 0 and state.analysis_samples == 0)
|
||||
state.finish_visit(captain,true)
|
||||
assert(state.analysis_samples == samples_before and samples_before == 7)
|
||||
assert(state.delivered_ammunition == ammo and captain.experience == xp and captain.credits == credits)
|
||||
for key in ["samples","credits","experience","ammunition","missile","irradiated_ammunition"]: assert(not captain.minerals.has(key))
|
||||
assert(state.analysis_samples == samples and state.delivered_ammunition == ammo)
|
||||
assert(captain.credits == credits and captain.experience == xp)
|
||||
state.finish_visit(captain,true)
|
||||
assert(state.analysis_samples == 7 and captain.credits == credits)
|
||||
assert(state.analysis_samples == samples and captain.credits == credits)
|
||||
assert(state.begin_visit(profile))
|
||||
state.add_material("samples",4)
|
||||
state.add_material("experience",999)
|
||||
state.add_material("ammunition",99)
|
||||
state.add_material("samples",99)
|
||||
state.add_material("credits",999)
|
||||
state.finish_visit(captain,false)
|
||||
assert(state.analysis_samples == 7 and captain.experience == xp and state.delivered_ammunition == ammo)
|
||||
for seed_value in 100:
|
||||
for stage in 3:
|
||||
var easy := RandomNumberGenerator.new()
|
||||
var hard := RandomNumberGenerator.new()
|
||||
easy.seed = seed_value
|
||||
hard.seed = seed_value
|
||||
var a := RULES.reward("warehouse",stage,easy,{"difficulty":0.0},captain)
|
||||
var b := RULES.reward("warehouse",stage,hard,{"difficulty":1.0},captain)
|
||||
for key in a:
|
||||
assert(b[key] == a[key]*(3 if key in ["iron","titanium","aluminium","uranium","sulfur"] else 1))
|
||||
var saved := "user://poi_samples_test.tres"
|
||||
assert(ResourceSaver.save(captain,saved) == OK)
|
||||
var loaded: Resource = ResourceLoader.load(saved,"",ResourceLoader.CACHE_MODE_IGNORE)
|
||||
assert(loaded.expedition.analysis_samples == 7)
|
||||
DirAccess.remove_absolute(saved)
|
||||
print("POI REWARDS PASS: all 15 stages, exact module levels, rare deposits, ammo scaling, EXP, samples, return/loss, persistence, duplicate claims")
|
||||
assert(state.analysis_samples == samples and captain.credits == credits)
|
||||
var hard := profile.duplicate()
|
||||
hard.oxygen = 0
|
||||
hard.temperature = 100
|
||||
hard.flora = 50
|
||||
# Keep biome richness equal: isolate effective hazards and equipped protection.
|
||||
for kind in RULES.KINDS:
|
||||
for seed_value in 20:
|
||||
set_gear(captain,0)
|
||||
rng.seed = seed_value
|
||||
var poor := RULES.reward(kind,rng,hard,captain)
|
||||
var poor_count := RULES.module_count(hard,captain)
|
||||
set_gear(captain,50)
|
||||
rng.seed = seed_value
|
||||
var protected := RULES.reward(kind,rng,hard,captain)
|
||||
for key in poor: assert(protected[key] >= poor[key])
|
||||
assert(RULES.module_count(hard,captain) > poor_count)
|
||||
if not poor.is_empty(): assert(protected.values() != poor.values())
|
||||
set_gear(captain,0)
|
||||
assert(PROFILES.poi_loot_report(hard,captain).multiplier < PROFILES.poi_loot_report(profile,captain).multiplier)
|
||||
assert(state.begin_visit(hard))
|
||||
state.lander_hp = 100
|
||||
var dangerous := {"kind":"ruins","complete":false}
|
||||
assert(state.resolve_poi(captain,dangerous,rng).success and dangerous.complete)
|
||||
assert(state.lander_hp == 100,"Ordinary POIs always give loot without a failure roll")
|
||||
for kind in ["hermit","time_engineer","crew","deep_deposit"]:
|
||||
assert(state.resolve_poi(captain,{"kind":kind,"complete":false},rng).is_empty())
|
||||
state.finish_visit(captain,true)
|
||||
var path := "res://tmp/poi_rewards_roundtrip.tres"
|
||||
assert(ResourceSaver.save(captain,path) == OK)
|
||||
var restored: Resource = ResourceLoader.load(path,"",ResourceLoader.CACHE_MODE_IGNORE)
|
||||
assert(restored.expedition.analysis_samples == samples)
|
||||
DirAccess.remove_absolute(path)
|
||||
print("POI_REWARDS_TEST: PASS (five single-visit kinds, immediate guaranteed loot, no damage/duplicates, protected return/loss, equipment and threat quantity scaling, special services excluded, persistence)")
|
||||
get_tree().quit()
|
||||
|
||||
48
tests/levels/ruins_loot_layout_test.gd
Normal file
@ -0,0 +1,48 @@
|
||||
extends Node
|
||||
|
||||
func settle() -> void:
|
||||
for frame in 12: await get_tree().process_frame
|
||||
await RenderingServer.frame_post_draw
|
||||
|
||||
func check_rows(surface: Control) -> void:
|
||||
var rows: Array[Node] = surface._choices.find_children("*","HBoxContainer",true,false)
|
||||
assert(rows.size() == 3)
|
||||
for row in rows:
|
||||
var label: Label = row.get_node("LootModuleName")
|
||||
assert(label.size.x > 200,"Name must fill the space beside its fixed-size icon")
|
||||
assert(label.get_line_count() <= 3,"Module names must not wrap letter by letter")
|
||||
assert(row.size.y < 90,"Each module must fit a compact row")
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
if not InputMap.has_action("ship_mini_boost"): InputMap.add_action("ship_mini_boost")
|
||||
var captain := GameState.captain
|
||||
for gear in captain.gear_items: gear.level = 50
|
||||
var profile := {"id":"ruins-layout","name":"Asteria","seed":8428159,"difficulty":0.4,"landing_damage":5,"oxygen":55,"temperature":55,"flora":10,"easy":false,"system_level":7}
|
||||
assert(captain.expedition.begin_visit(profile))
|
||||
var layer := CanvasLayer.new()
|
||||
add_child(layer)
|
||||
var surface := Control.new()
|
||||
surface.set_script(preload("res://scripts/planets/surface_screen.gd"))
|
||||
surface.captain = captain
|
||||
surface.progress = captain.expedition
|
||||
layer.add_child(surface)
|
||||
surface.set_process(false)
|
||||
surface.set_physics_process(false)
|
||||
var poi: Dictionary = surface.world.data.pois[0]
|
||||
poi.kind = "ruins"
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = 100
|
||||
var result: Dictionary = captain.expedition.resolve_poi(captain,poi,rng)
|
||||
assert(result.modules.size() == 3)
|
||||
result.modules[0].definition = preload("res://resources/items/ship_computer.tres")
|
||||
surface._poi = poi
|
||||
surface._show_poi()
|
||||
await settle()
|
||||
check_rows(surface)
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/ruins_loot_layout_fixed.png") == OK)
|
||||
get_window().size = Vector2i(800,600)
|
||||
await settle()
|
||||
check_rows(surface)
|
||||
print("RUINS LOOT LAYOUT PASS: 3 modules including computer, readable names and compact rows at 1280x720 and 800x600")
|
||||
get_tree().quit()
|
||||
1
tests/levels/ruins_loot_layout_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bp21grw1a8ism
|
||||
4
tests/levels/ruins_loot_layout_test.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/levels/ruins_loot_layout_test.gd" id="1"]
|
||||
[node name="RuinsLootLayoutTest" type="Node"]
|
||||
script = ExtResource("1")
|
||||
68
tests/levels/single_visit_surface_test.gd
Normal file
@ -0,0 +1,68 @@
|
||||
extends Node
|
||||
|
||||
const SCREEN := preload("res://scripts/planets/surface_screen.gd")
|
||||
|
||||
func _ready() -> void:
|
||||
if not InputMap.has_action("ship_mini_boost"):
|
||||
InputMap.add_action("ship_mini_boost")
|
||||
GameState.start_new_run()
|
||||
GameState.system_level = 7
|
||||
var captain := GameState.captain
|
||||
for gear in captain.gear_items: gear.level = 12
|
||||
var progress: Resource = captain.expedition
|
||||
var profile := {"id":"single-visit-ui","name":"Asteria","seed":8428159,"difficulty":0.4,"landing_damage":5,"oxygen":55,"temperature":55,"flora":10,"easy":false,"system_level":7}
|
||||
assert(progress.begin_visit(profile))
|
||||
var layer := CanvasLayer.new()
|
||||
add_child(layer)
|
||||
var surface := Control.new()
|
||||
surface.set_script(SCREEN)
|
||||
surface.captain = captain
|
||||
surface.progress = progress
|
||||
layer.add_child(surface)
|
||||
surface.set_process(false)
|
||||
surface.set_physics_process(false)
|
||||
# Keep optional encounter popups away from the ordinary POI fixture.
|
||||
for event in surface.world.data.events: event.position = Vector2(10000,10000)
|
||||
var poi: Dictionary = surface.world.data.pois[0]
|
||||
assert(poi.kind == "warehouse")
|
||||
surface.lander.position = poi.position
|
||||
surface._previous_position = poi.position
|
||||
surface.camera.position = poi.position
|
||||
surface.camera.reset_smoothing()
|
||||
surface.world.refresh_pois(poi.position)
|
||||
assert(surface.world._poi_labels[poi.id].text.contains("[E]"))
|
||||
var key := InputEventKey.new()
|
||||
key.pressed = true
|
||||
key.keycode = KEY_E
|
||||
var permanent := captain.minerals.duplicate()
|
||||
surface._input(key)
|
||||
assert(surface._dialog.visible and poi.complete and not progress.cargo.is_empty())
|
||||
assert(captain.minerals == permanent,"Loot waits in expedition cargo until safe return")
|
||||
var labels := ""
|
||||
for label in surface._choices.find_children("*","Label",true,false): labels += label.text+"\n"
|
||||
assert(labels.contains("ZDOBYTO") and not labels.contains("ETAP") and not labels.contains("Powodzenie"))
|
||||
var snapshot: Dictionary = progress.cargo.duplicate()
|
||||
if not DisplayServer.get_name() == "headless":
|
||||
for frame in 12: await get_tree().process_frame
|
||||
await RenderingServer.frame_post_draw
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/single_visit_planet_poi.png") == OK)
|
||||
surface._input(key)
|
||||
assert(not surface._dialog.visible and progress.cargo == snapshot)
|
||||
surface._input(key)
|
||||
assert(not surface._dialog.visible and progress.cargo == snapshot,"Repeated E cannot reclaim visited POIs")
|
||||
# Services keep their own interfaces and do not become auto-collected loot.
|
||||
for kind in ["time_engineer","hermit","crew","deep_deposit"]:
|
||||
var special := {"kind":kind,"complete":false}
|
||||
surface._poi = special
|
||||
surface._show_poi()
|
||||
assert(surface._dialog.visible and not special.complete)
|
||||
assert(progress.cargo == snapshot)
|
||||
surface._dialog.hide()
|
||||
var encounter := {"kind":"trader","seed":42,"complete":false}
|
||||
surface._show_event(encounter)
|
||||
assert(surface._dialog.visible and not encounter.complete)
|
||||
assert(surface._poi.is_empty(),"Previous result must not hijack event interaction")
|
||||
surface._input(key)
|
||||
assert(surface._dialog.visible)
|
||||
print("SINGLE_VISIT_SURFACE_TEST: PASS (E immediately grants loot and opens results, no stages, close/repeat safety, pending cargo, engineers/cartographer/crew/deposit and question-mark events retained)")
|
||||
get_tree().quit()
|
||||
1
tests/levels/single_visit_surface_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c28qv5rytnl2e
|
||||
4
tests/levels/single_visit_surface_test.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/levels/single_visit_surface_test.gd" id="1"]
|
||||
[node name="SingleVisitSurfaceTest" type="Node"]
|
||||
script = ExtResource("1")
|
||||
1
tests/previews/auxiliary_shield_live_demo.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://5ek8d3a7hfg8
|
||||
1
tests/previews/auxiliary_shield_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://3mvkf1ohrd8p
|
||||
24
tests/previews/captain_skill_frames_preview.gd
Normal file
@ -0,0 +1,24 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
var captain := GameState.captain
|
||||
var catalog := preload("res://scripts/captain/captain_skills.gd")
|
||||
for id in catalog.IDS:
|
||||
if id not in ["scrap_collector","drone_commander"]: captain.skills[id] = 1
|
||||
var game := preload("res://scenes/game/game.tscn").instantiate()
|
||||
add_child(game)
|
||||
game.set_physics_process(false)
|
||||
game.player.set_physics_process(false)
|
||||
game.player.get_node("WeaponController").set_physics_process(false)
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"): enemy.set_physics_process(false)
|
||||
var ui: CanvasLayer = game.find_child("CaptainSkills",true,false)
|
||||
captain.learning_points = 1
|
||||
captain.skill_offers.assign(["scrap_collector","drone_commander"])
|
||||
ui.open_management()
|
||||
for index in 12: await get_tree().process_frame
|
||||
await RenderingServer.frame_post_draw
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/captain_skill_frames.png") == OK)
|
||||
print("SALVAGE_DRONE_SKILLS_PREVIEW: PASS")
|
||||
get_tree().quit()
|
||||
|
||||
1
tests/previews/captain_skill_frames_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d0xnuul26qx1r
|
||||
5
tests/previews/captain_skill_frames_preview.tscn
Normal file
@ -0,0 +1,5 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/captain_skill_frames_preview.gd" id="1"]
|
||||
[node name="SalvageDroneSkillsPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
|
||||
27
tests/previews/hermit_grounding_preview.gd
Normal file
@ -0,0 +1,27 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
var profile := {"id":"hermit-preview","name":"Asteria","seed":8428159,"difficulty":0.4,"landing_damage":5,"oxygen":55,"temperature":55,"flora":10,"easy":false,"system_level":7}
|
||||
assert(GameState.captain.expedition.begin_visit(profile))
|
||||
var data: Dictionary = preload("res://scripts/planets/surface_generator.gd").generate(8428159,profile)
|
||||
var kind := "time_engineer" if "--engineer" in OS.get_cmdline_user_args() else "hermit"
|
||||
data.pois[0].kind = kind
|
||||
data.pois[0].position = Vector2.ZERO
|
||||
var world := Node2D.new()
|
||||
world.set_script(preload("res://scripts/planets/surface_world.gd"))
|
||||
world.data = data
|
||||
add_child(world)
|
||||
var camera := Camera2D.new()
|
||||
camera.zoom = Vector2.ONE*3.0
|
||||
camera.position = Vector2(0,8)
|
||||
add_child(camera)
|
||||
world.refresh_pois(Vector2.ZERO)
|
||||
var building: Sprite2D = world._poi_sprites[data.pois[0].id]
|
||||
assert(building.material != null and building.has_node("GroundContact"))
|
||||
assert(building.texture.get_image().detect_alpha() != Image.ALPHA_NONE)
|
||||
for frame in 12: await get_tree().process_frame
|
||||
await RenderingServer.frame_post_draw
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/%s_grounded_preview.png" % kind) == OK)
|
||||
print("HERMIT GROUNDING PREVIEW PASS: replacement sprite, alpha, biome material, contact shadow and service marker")
|
||||
get_tree().quit()
|
||||
1
tests/previews/hermit_grounding_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cu5exn8c3d38s
|
||||
4
tests/previews/hermit_grounding_preview.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/hermit_grounding_preview.gd" id="1"]
|
||||
[node name="HermitGroundingPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
48
tests/previews/loot_reveal_preview.gd
Normal file
@ -0,0 +1,48 @@
|
||||
extends Node2D
|
||||
|
||||
const EFFECT := preload("res://scripts/items/loot_reveal_effect.gd")
|
||||
|
||||
func _ready() -> void:
|
||||
RenderingServer.set_default_clear_color(Color("081420"))
|
||||
var title := Label.new()
|
||||
title.text = "ODZYSKANE WYPOSAŻENIE"
|
||||
title.position = Vector2(85,65)
|
||||
title.add_theme_font_size_override("font_size",28)
|
||||
add_child(title)
|
||||
var effects: Array[Node2D] = []
|
||||
for index in 3:
|
||||
var item := ItemInstance.new()
|
||||
item.definition = preload("res://resources/items/reinforced_shield.tres")
|
||||
item.rarity = index*2
|
||||
for addon in index*2+1:
|
||||
var modifier := ItemStatModifier.new()
|
||||
modifier.stat_key = "shield_percent"
|
||||
modifier.value = 1.0
|
||||
item.additional_modifiers.append(modifier)
|
||||
var pickup := Node2D.new()
|
||||
pickup.set_script(preload("res://scripts/items/loot_pickup.gd"))
|
||||
pickup.item = item
|
||||
pickup.position = Vector2(250+index*350,350)
|
||||
add_child(pickup)
|
||||
var label := Label.new()
|
||||
label.text = item.get_rarity_name()
|
||||
label.position = pickup.position+Vector2(-65,85)
|
||||
label.add_theme_font_size_override("font_size",18)
|
||||
label.modulate = item.get_rarity_color()
|
||||
add_child(label)
|
||||
for child in get_children():
|
||||
if child.get_script() == EFFECT: effects.append(child)
|
||||
assert(effects.size() == 3)
|
||||
var normal := EFFECT.sound(0)
|
||||
assert(normal.get_length() > 0.6 and normal.data.size() > 20000)
|
||||
assert(normal == EFFECT.sound(0) and normal != EFFECT.sound(1))
|
||||
assert(normal.save_to_wav("res://artifacts/loot_drop_chime.wav") == OK)
|
||||
await get_tree().create_timer(0.18).timeout
|
||||
if DisplayServer.get_name() != "headless":
|
||||
await RenderingServer.frame_post_draw
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/loot_drop_effect.png") == OK)
|
||||
await get_tree().create_timer(0.9).timeout
|
||||
for effect in effects: assert(not is_instance_valid(effect))
|
||||
assert(get_tree().get_nodes_in_group("loot").size() == 3)
|
||||
print("LOOT REVEAL PASS: three rarity drops, cached sound synthesis, preview and WAV export, timed effect cleanup, loot retained")
|
||||
get_tree().quit()
|
||||
1
tests/previews/loot_reveal_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://g8ybogggsyc5
|
||||
4
tests/previews/loot_reveal_preview.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/loot_reveal_preview.gd" id="1"]
|
||||
[node name="LootRevealPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
@ -42,12 +42,8 @@ func _ready() -> void:
|
||||
gear.level = scenario.rank
|
||||
GameState.captain.emit_changed()
|
||||
await capture(scenario.name)
|
||||
assert(manager._text.text.contains("ŚREDNIA SZANSA POI"))
|
||||
assert(manager._text.text.contains("ŁUP POI"))
|
||||
assert(get_viewport().get_visible_rect().encloses(manager._prompt.get_global_rect()))
|
||||
if scenario.rank == 1 or scenario.rank == 50:
|
||||
assert(manager._text.text.contains("66.7%"))
|
||||
else:
|
||||
assert(manager._text.text.contains("6.7%"))
|
||||
for gear in GameState.captain.gear_items:
|
||||
gear.level = 25
|
||||
GameState.captain.emit_changed()
|
||||
@ -57,16 +53,10 @@ func _ready() -> void:
|
||||
surface.set_process(false)
|
||||
surface.set_physics_process(false)
|
||||
var poi: Dictionary = surface.world.data.pois[0]
|
||||
poi.stage = 2
|
||||
surface._poi = poi
|
||||
surface._show_poi()
|
||||
var blocked_poi := false
|
||||
for child in surface._choices.get_children():
|
||||
if child is Button and child.text.contains("0.00% szans"):
|
||||
assert(child.disabled)
|
||||
blocked_poi = true
|
||||
assert(blocked_poi)
|
||||
await capture("zero_chance_poi")
|
||||
assert(poi.complete and not surface.progress.cargo.is_empty())
|
||||
await capture("single_visit_poi")
|
||||
var event := {"kind":"evacuation","seed":77,"position":Vector2.ZERO,"complete":false}
|
||||
EVENTS.prepare(event,GameState.captain,surface.progress)
|
||||
event.stage = 2
|
||||
@ -84,5 +74,5 @@ func _ready() -> void:
|
||||
manager.finish_surface(true)
|
||||
game.queue_free()
|
||||
await get_tree().process_frame
|
||||
print("THREAT UI PASS: three prelanding scans, visible averaged odds, L50 mitigation, on-screen prompt, disabled zero-chance POI and event, rescue threat")
|
||||
print("THREAT UI PASS: three prelanding loot scans, L50 mitigation, on-screen prompt, single-visit POI, disabled zero-chance special event, rescue threat")
|
||||
get_tree().quit()
|
||||
|
||||
24
tests/previews/shield_performance_test.gd
Normal file
@ -0,0 +1,24 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
||||
Engine.max_fps = 0
|
||||
var baseline := "--baseline" in OS.get_cmdline_user_args()
|
||||
var script: Script = load("res://tmp/shield_visual_before_optimization.gd" if baseline else "res://scripts/game/shield_visual.gd")
|
||||
var shields: Array[Node2D] = []
|
||||
for index in 120:
|
||||
var shield := Node2D.new()
|
||||
shield.set_script(script)
|
||||
shield.shield_radius = 24.0
|
||||
shield.position = Vector2(55+(index%15)*82,65+(index/15)*80)
|
||||
add_child(shield)
|
||||
shields.append(shield)
|
||||
for frame in 30: await get_tree().process_frame
|
||||
var start := Time.get_ticks_usec()
|
||||
var draw_calls := 0.0
|
||||
for frame in 150:
|
||||
for shield in shields: shield.set_shield_values(100,100)
|
||||
await get_tree().process_frame
|
||||
draw_calls += Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)
|
||||
print("SHIELD PERFORMANCE %s: 120 shields, average %.3f ms/frame, %.1f draw calls/frame" % ["BEFORE" if baseline else "AFTER",(Time.get_ticks_usec()-start)/150000.0,draw_calls/150.0])
|
||||
get_tree().quit()
|
||||
1
tests/previews/shield_performance_test.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://0yqov2w2fjhv
|
||||
4
tests/previews/shield_performance_test.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/shield_performance_test.gd" id="1"]
|
||||
[node name="ShieldPerformanceTest" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
36
tests/previews/shield_polish_preview.gd
Normal file
@ -0,0 +1,36 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
GameState.start_new_run()
|
||||
RenderingServer.set_default_clear_color(Color("071420"))
|
||||
var heading := Label.new()
|
||||
heading.text = "POLE OCHRONNE · TARCZA STATKU"
|
||||
heading.position = Vector2(90,65)
|
||||
heading.add_theme_font_size_override("font_size",26)
|
||||
add_child(heading)
|
||||
for index in 3:
|
||||
var ship := preload("res://scenes/game/player_ship.tscn").instantiate()
|
||||
ship.get_node("Camera2D").enabled = false
|
||||
add_child(ship)
|
||||
ship.position = Vector2(260+index*380,350)
|
||||
ship.scale = Vector2.ONE*1.8
|
||||
ship.set_physics_process(false)
|
||||
ship.get_node("WeaponController").set_physics_process(false)
|
||||
var shield := ship.get_node("ShieldVisual")
|
||||
shield.set_shield_values(20.0 if index == 1 else 100.0,100.0)
|
||||
shield.set_process(false)
|
||||
shield._time = 0.5
|
||||
if index == 2:
|
||||
shield.flash_hit(ship.global_position+Vector2(100,-80))
|
||||
shield._hits[0].age = 0.06
|
||||
var label := Label.new()
|
||||
label.text = ["PEŁNE TARCZE","NISKA MOC OSŁONY","TRAFIENIE W POLE"][index]
|
||||
label.position = ship.position+Vector2(-105,140)
|
||||
label.add_theme_font_size_override("font_size",16)
|
||||
label.modulate = Color("91dbea")
|
||||
add_child(label)
|
||||
for frame in 12: await get_tree().process_frame
|
||||
await RenderingServer.frame_post_draw
|
||||
assert(get_viewport().get_texture().get_image().save_png("res://artifacts/shield_polish.png") == OK)
|
||||
print("SHIELD POLISH PREVIEW PASS: full/low shield and directional impact rendered")
|
||||
get_tree().quit()
|
||||
1
tests/previews/shield_polish_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c1wbj13mf84j1
|
||||
4
tests/previews/shield_polish_preview.tscn
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
[ext_resource type="Script" path="res://tests/previews/shield_polish_preview.gd" id="1"]
|
||||
[node name="ShieldPolishPreview" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
63
tmp/captain_skill_frames.log
Normal file
@ -0,0 +1,63 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6571
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: Camera2D overridden to physics process mode due to use of physics interpolation.
|
||||
at: _update_process_callback (scene/2d/camera_2d.cpp:88)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] _ready (res://tests/previews/captain_skill_frames_preview.gd:10)
|
||||
SALVAGE_DRONE_SKILLS_PREVIEW: PASS
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
56
tmp/enemy_shield_damage_audit.log
Normal file
@ -0,0 +1,56 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6571
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot
|
||||
ENEMY SHIELD DAMAGE AUDIT PASS: no hull damage under full absorption, exact shield break survives, correct overflow/research scaling, no duplicate projectile damage, 10 hull hits after shield break; instant 0.05 shield regeneration confirmed
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
60
tmp/equipment_comparison_test.log
Normal file
@ -0,0 +1,60 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6572
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6572 registered for c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: Camera2D overridden to physics process mode due to use of physics interpolation.
|
||||
at: _update_process_callback (scene/2d/camera_2d.cpp:88)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] _ready (res://tests/items/equipment_comparison_test.gd:19)
|
||||
EQUIPMENT_COMPARISON_TEST: PASS primary difference, addon loss, duplicate addon sum, regeneration scaling, empty slot, unchanged stats, side column, compact debug, actual percentage effects match equipping
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
63
tmp/hermit_grounding_final.log
Normal file
@ -0,0 +1,63 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6571
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: Camera2D overridden to physics process mode due to use of physics interpolation.
|
||||
at: _update_process_callback (scene/2d/camera_2d.cpp:88)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] _ready (res://tests/previews/hermit_grounding_preview.gd:17)
|
||||
HERMIT GROUNDING PREVIEW PASS: replacement sprite, alpha, biome material, contact shadow and service marker
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
63
tmp/hermit_grounding_preview.log
Normal file
@ -0,0 +1,63 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6571
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6571 registered for c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: Camera2D overridden to physics process mode due to use of physics interpolation.
|
||||
at: _update_process_callback (scene/2d/camera_2d.cpp:88)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] _ready (res://tests/previews/hermit_grounding_preview.gd:17)
|
||||
HERMIT GROUNDING PREVIEW PASS: replacement sprite, alpha, biome material, contact shadow and service marker
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
156
tmp/hermit_import.log
Normal file
@ -0,0 +1,156 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Could not create editor data directory: C:/Users/Tomek/AppData/Roaming/Godot
|
||||
at: EditorPaths (editor/file_system/editor_paths.cpp:201)
|
||||
ERROR: Could not create editor config directory: C:/Users/Tomek/AppData/Roaming/Godot
|
||||
at: EditorPaths (editor/file_system/editor_paths.cpp:216)
|
||||
|
||||
ERROR: Could not open 'user://' directory: 'user://'.
|
||||
at: _get_and_create_snapshot_storage_dir (modules/objectdb_profiler/editor/objectdb_profiler_panel.cpp:157)
|
||||
ERROR: Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash.
|
||||
at: _close (drivers/windows/file_access_windows.cpp:277)
|
||||
ERROR: Cannot open directory 'C:/Users/Tomek/AppData/Roaming/Godot/feature_profiles'.
|
||||
at: _update_profile_list (editor/settings/editor_feature_profile.cpp:392)
|
||||
[ 0% ] first_scan_filesystem | Started Inicjalizacja projektu (5 steps)
|
||||
[ 0% ] first_scan_filesystem | Skanowanie struktury plików...
|
||||
[ 16% ] first_scan_filesystem | Wczytywanie globalnych nazw klas...
|
||||
[ 33% ] first_scan_filesystem | Weryfikowanie GDExtension...
|
||||
[ 50% ] first_scan_filesystem | Tworzenie skryptów autoładowania...
|
||||
[ 66% ] first_scan_filesystem | Inicjalizacja wtyczek...
|
||||
Godot MCP Toolkit v1.0.3 — by NPGameDev · npgamedev.com
|
||||
[MCPExtensions] Hot-reload watcher active
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] self_heal (res://addons/godot_mcp_toolkit/core/unfocused_sleep_controller.gd:171)
|
||||
[3] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:293)
|
||||
[4] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[5] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
SCRIPT ERROR: Invalid call. Nonexistent 'int' constructor.
|
||||
at: self_heal (res://addons/godot_mcp_toolkit/core/unfocused_sleep_controller.gd:173)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] self_heal (res://addons/godot_mcp_toolkit/core/unfocused_sleep_controller.gd:173)
|
||||
[1] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:293)
|
||||
[2] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[3] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
[MCPServer] port: scanning 6550-6560 (default)
|
||||
WARNING: [MCPServer] failed to write token (err 1); auth will still be enforced but bridge may not find the file
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:317)
|
||||
[1] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[2] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
[MCPServer] listening on 127.0.0.1:6551
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.json.tmp (err 1)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] _write_entry (res://addons/godot_mcp_toolkit/registry/registry_client.gd:88)
|
||||
[2] register (res://addons/godot_mcp_toolkit/registry/registry_client.gd:142)
|
||||
[3] _register_in_registry (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:129)
|
||||
[4] <anonymous lambda> (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:90)
|
||||
[5] _on_transport_bound (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:381)
|
||||
[6] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[7] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[8] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:322)
|
||||
[9] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[10] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] register (res://addons/godot_mcp_toolkit/registry/registry_client.gd:144)
|
||||
[3] _register_in_registry (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:129)
|
||||
[4] <anonymous lambda> (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:90)
|
||||
[5] _on_transport_bound (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:381)
|
||||
[6] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[7] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[8] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:322)
|
||||
[9] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[10] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 1)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] register (res://addons/godot_mcp_toolkit/registry/registry_client.gd:145)
|
||||
[4] _register_in_registry (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:129)
|
||||
[5] <anonymous lambda> (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:90)
|
||||
[6] _on_transport_bound (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:381)
|
||||
[7] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[8] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[9] start (res://addons/godot_mcp_toolkit/transport/mcp_server.gd:322)
|
||||
[10] compose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:91)
|
||||
[11] _enter_tree (res://addons/godot_mcp_toolkit/plugin.gd:47)
|
||||
[MCPRegistry] registered c:/users/tomek/documents/godot/randoloot on port 6551
|
||||
[ 83% ] first_scan_filesystem | Uruchamianie skanu systemu plików...
|
||||
[ DONE ] first_scan_filesystem
|
||||
|
||||
[ 0% ] update_scripts_classes | Started Rejestrowanie globalnych klas... (2 steps)
|
||||
[ 0% ] update_scripts_classes |
|
||||
[ 33% ] update_scripts_classes |
|
||||
[ DONE ] update_scripts_classes
|
||||
|
||||
[ 0% ] reimport | Started (Ponowne) importowanie zasobów (1 steps)
|
||||
[ 0% ] reimport | Przygotowywanie plików do ponownego importu...
|
||||
[ 0% ] reimport | Wykonywanie operacji przed importem...
|
||||
[ 0% ] reimport | hermit_cartographer_grounded.png
|
||||
[ 50% ] reimport | Finalizowanie importu zasobów...
|
||||
[ DONE ] reimport
|
||||
|
||||
[ 0% ] reimport | Started (Ponowne) importowanie zasobów (1 steps)
|
||||
[ 0% ] reimport | Wykonywanie operacji po imporcie...
|
||||
[ DONE ] reimport
|
||||
|
||||
[ 0% ] loading_editor_layout | Started Wczytywanie edytora (5 steps)
|
||||
[ 0% ] loading_editor_layout | Wczytywanie układu edytora...
|
||||
[ 16% ] loading_editor_layout | Wczytywanie doków...
|
||||
[ 33% ] loading_editor_layout | Przywracanie scen...
|
||||
[ 50% ] loading_editor_layout | Wczytywanie centralnego układu edytora...
|
||||
[ 66% ] loading_editor_layout | Wczytywanie układu okien wtyczek...
|
||||
[ 83% ] loading_editor_layout | Układ edytora gotowy.
|
||||
[ DONE ] loading_editor_layout
|
||||
|
||||
[MCPServer] stopped
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] deregister (res://addons/godot_mcp_toolkit/registry/registry_client.gd:153)
|
||||
[3] dispose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:298)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/plugin.gd:113)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 1)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] deregister (res://addons/godot_mcp_toolkit/registry/registry_client.gd:154)
|
||||
[4] dispose (res://addons/godot_mcp_toolkit/core/plugin_composer.gd:298)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/plugin.gd:113)
|
||||
[MCPRegistry] deregistered c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:195)
|
||||
[3] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[4] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 1)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] clear_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:196)
|
||||
[4] _stop_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:193)
|
||||
[5] _exit_tree (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:115)
|
||||
ERROR: Can't save resource to empty path. Provide non-empty path or a Resource with non-empty resource_path.
|
||||
at: save (core/io/resource_saver.cpp:108)
|
||||
ERROR: Error saving editor settings to
|
||||
at: save (editor/settings/editor_settings.cpp:1525)
|
||||
42
tmp/loot_reveal_preview.log
Normal file
@ -0,0 +1,42 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6570
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot
|
||||
LOOT REVEAL PASS: three rarity drops, cached sound synthesis, preview and WAV export, timed effect cleanup, loot retained
|
||||
39
tmp/loot_reveal_ui.log
Normal file
@ -0,0 +1,39 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6570
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot
|
||||
SINGLE_VISIT_SURFACE_TEST: PASS (E immediately grants loot and opens results, no stages, close/repeat safety, pending cargo, engineers/cartographer/crew/deposit and question-mark events retained)
|
||||
54
tmp/ruins_loot_layout.log
Normal file
@ -0,0 +1,54 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6570
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot
|
||||
SCRIPT ERROR: Assertion failed.
|
||||
at: check_rows (res://tests/levels/ruins_loot_layout_test.gd:9)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] check_rows (res://tests/levels/ruins_loot_layout_test.gd:9)
|
||||
[1] _ready (res://tests/levels/ruins_loot_layout_test.gd:42)
|
||||
[2] settle (res://tests/levels/ruins_loot_layout_test.gd:5)
|
||||
SCRIPT ERROR: Assertion failed.
|
||||
at: check_rows (res://tests/levels/ruins_loot_layout_test.gd:9)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] check_rows (res://tests/levels/ruins_loot_layout_test.gd:9)
|
||||
[1] _ready (res://tests/levels/ruins_loot_layout_test.gd:46)
|
||||
[2] settle (res://tests/levels/ruins_loot_layout_test.gd:5)
|
||||
RUINS LOOT LAYOUT PASS: 3 modules including computer, readable names and compact rows at 1280x720 and 800x600
|
||||
42
tmp/ruins_loot_layout_final.log
Normal file
@ -0,0 +1,42 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
ERROR: Can't create shader cache folder, no shader caching will happen: user://
|
||||
at: RasterizerGLES3 (drivers/gles3/rasterizer_gles3.cpp:345)
|
||||
OpenGL API 3.3.0 NVIDIA 610.88 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 SUPER
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6570
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot
|
||||
RUINS LOOT LAYOUT PASS: 3 modules including computer, readable names and compact rows at 1280x720 and 800x600
|
||||
43
tmp/shield_cached_auxiliary.log
Normal file
@ -0,0 +1,43 @@
|
||||
Godot Engine v4.7.2.stable.official.ed1daf0bf - https://godotengine.org
|
||||
|
||||
[MCPRuntimeServer] port: scanning 6570-6585 (default)
|
||||
[MCPRuntimeServer] listening on 127.0.0.1:6570
|
||||
WARNING: [MCPRegistry] cannot write entry C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/entries/32cc2271ac67.runtime.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write (res://addons/godot_mcp_toolkit/registry/store/registry_entry_file.gd:29)
|
||||
[1] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:181)
|
||||
[2] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[3] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[4] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[5] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[6] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] failed to acquire lock after 10 retries; proceeding anyway
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] acquire (res://addons/godot_mcp_toolkit/registry/store/file_lock.gd:58)
|
||||
[1] acquire_lock (res://addons/godot_mcp_toolkit/registry/registry_client.gd:75)
|
||||
[2] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:182)
|
||||
[3] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[4] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[5] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[6] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[7] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
WARNING: [MCPRegistry] cannot write C:\Users\Tomek\AppData\Roaming/godot-mcp-toolkit/projects.json.tmp (err 12)
|
||||
at: push_warning (core/variant/variant_utility.cpp:1033)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] write_atomic (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:35)
|
||||
[1] rebuild (res://addons/godot_mcp_toolkit/registry/store/registry_projection.gd:88)
|
||||
[2] _rebuild_projects_json (res://addons/godot_mcp_toolkit/registry/registry_client.gd:114)
|
||||
[3] set_runtime (res://addons/godot_mcp_toolkit/registry/registry_client.gd:183)
|
||||
[4] _on_bound (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:200)
|
||||
[5] _scan_and_listen (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:283)
|
||||
[6] ensure_listening (res://addons/godot_mcp_toolkit/transport/ws_transport.gd:254)
|
||||
[7] _start_server (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:162)
|
||||
[8] _ready (res://addons/godot_mcp_toolkit/runtime/mcp_runtime_server.gd:111)
|
||||
[MCPRegistry] runtime port 6570 registered for c:/users/tomek/documents/godot/randoloot
|
||||
WARNING: Camera2D overridden to physics process mode due to use of physics interpolation.
|
||||
at: _update_process_callback (scene/2d/camera_2d.cpp:88)
|
||||
GDScript backtrace (most recent call first):
|
||||
[0] _ready (res://tests/abilities/auxiliary_shield_test.gd:23)
|
||||
AUXILIARY_SHIELD_TEST: PASS (lab unlock, 70% max energy cost, 50% max shield snapshot, no stacking, outer-first damage and overflow, larger bullet/laser collision with empty main shields, cooldown, reset, power redirect and docking)
|
||||