This commit is contained in:
Tomasz Boruc 2026-10-26 21:06:32 +01:00
parent 23ebb4ad4c
commit 18d9bcc9a4
118 changed files with 3011 additions and 201 deletions

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View 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

Binary file not shown.

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View 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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View 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

View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View 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

View 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.

View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View 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

View 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;
}

View File

@ -0,0 +1 @@
uid://bon0cmiaqj514

View File

@ -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"

View File

@ -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"

View 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;
}

View File

@ -0,0 +1 @@
uid://r0qkep3cb68g

View File

@ -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()

View File

@ -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)

View File

@ -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:

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View 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)

View File

@ -0,0 +1 @@
uid://552wjksemhnb

View File

@ -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))

View File

@ -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:

View 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))

View File

@ -0,0 +1 @@
uid://1hyakl7p27h5

View File

@ -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)]

View File

@ -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
if str(poi.kind) == "ruins":
var item: ItemInstance = REWARDS.generate_module(rng,active_profile,GameState.system_level,null,0,stage+1)
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":
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

View File

@ -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)

View File

@ -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)
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.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)]] = 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)

View File

@ -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:

View File

@ -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():

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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)

View 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()

View File

@ -0,0 +1 @@
uid://bpuveichg42sd

View 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")

View 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()

View File

@ -0,0 +1 @@
uid://djqy5y0d6h7s2

View 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")

View File

@ -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()

View File

@ -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})

View File

@ -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")

View File

@ -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}
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))
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)
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)
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.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()

View 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()

View File

@ -0,0 +1 @@
uid://bp21grw1a8ism

View 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")

View 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()

View File

@ -0,0 +1 @@
uid://c28qv5rytnl2e

View 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")

View File

@ -0,0 +1 @@
uid://5ek8d3a7hfg8

View File

@ -0,0 +1 @@
uid://3mvkf1ohrd8p

View 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()

View File

@ -0,0 +1 @@
uid://d0xnuul26qx1r

View 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")

View 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()

View File

@ -0,0 +1 @@
uid://cu5exn8c3d38s

View 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")

View 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()

View File

@ -0,0 +1 @@
uid://g8ybogggsyc5

View 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")

View File

@ -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()

View 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()

View File

@ -0,0 +1 @@
uid://0yqov2w2fjhv

View 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")

View 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()

View File

@ -0,0 +1 @@
uid://c1wbj13mf84j1

View 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")

View 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)

View 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)

View 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)

View 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)

View 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
View 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)

View 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
View 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
View 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

View 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

View 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)

Some files were not shown because too many files have changed in this diff Show More