Zmiany tubylców
This commit is contained in:
parent
a74319d01e
commit
72925fd557
BIN
artifacts/planet_services_preview.png
Normal file
BIN
artifacts/planet_services_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
40
artifacts/planet_services_preview.png.import
Normal file
40
artifacts/planet_services_preview.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cdy2tv4him7u4"
|
||||||
|
path="res://.godot/imported/planet_services_preview.png-30cacc45a7eb1c9740376c061502ca8d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://artifacts/planet_services_preview.png"
|
||||||
|
dest_files=["res://.godot/imported/planet_services_preview.png-30cacc45a7eb1c9740376c061502ca8d.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
|
||||||
@ -7,7 +7,7 @@ icon = ExtResource("icon")
|
|||||||
item_id = "gamma_cannon"
|
item_id = "gamma_cannon"
|
||||||
display_name = "Działko gamma"
|
display_name = "Działko gamma"
|
||||||
category = 0
|
category = 0
|
||||||
description = "Radiacyjna kula. Napromieniowanie: 3 s, 25% obrażeń trafienia/s. Kolejne trafienia odświeżają czas. Zużywa napromieniowaną amunicję."
|
description = "Radiacyjna kula. Napromieniowanie: 10 s, 25% obrażeń trafienia/s. Kolejne trafienia odświeżają czas. Zużywa napromieniowaną amunicję."
|
||||||
primary_stat = "damage"
|
primary_stat = "damage"
|
||||||
primary_value = 15.0
|
primary_value = 15.0
|
||||||
stat_suffix = " DMG"
|
stat_suffix = " DMG"
|
||||||
|
|||||||
@ -3,16 +3,16 @@
|
|||||||
[ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"]
|
[ext_resource type="Script" path="res://scripts/ui/planet_services_menu.gd" id="1_services"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="PanelStyle"]
|
[sub_resource type="StyleBoxFlat" id="PanelStyle"]
|
||||||
bg_color = Color(0.045, 0.075, 0.11, 0.64)
|
bg_color = Color(0.025, 0.045, 0.065, 0.94)
|
||||||
border_width_left = 1
|
border_width_left = 1
|
||||||
border_width_top = 1
|
border_width_top = 1
|
||||||
border_width_right = 1
|
border_width_right = 1
|
||||||
border_width_bottom = 1
|
border_width_bottom = 1
|
||||||
border_color = Color(0.28, 0.63, 0.54, 1)
|
border_color = Color(0.28, 0.63, 0.54, 1)
|
||||||
content_margin_left = 14.0
|
content_margin_left = 10.0
|
||||||
content_margin_top = 14.0
|
content_margin_top = 10.0
|
||||||
content_margin_right = 14.0
|
content_margin_right = 10.0
|
||||||
content_margin_bottom = 14.0
|
content_margin_bottom = 10.0
|
||||||
corner_radius_top_left = 8
|
corner_radius_top_left = 8
|
||||||
corner_radius_top_right = 8
|
corner_radius_top_right = 8
|
||||||
corner_radius_bottom_left = 8
|
corner_radius_bottom_left = 8
|
||||||
@ -21,7 +21,7 @@ corner_radius_bottom_right = 8
|
|||||||
[node name="PlanetServicesMenu" type="Control"]
|
[node name="PlanetServicesMenu" type="Control"]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 350.0
|
offset_right = 320.0
|
||||||
offset_bottom = 250.0
|
offset_bottom = 250.0
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
script = ExtResource("1_services")
|
script = ExtResource("1_services")
|
||||||
@ -34,18 +34,18 @@ anchor_bottom = 1.0
|
|||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
|
||||||
[node name="Panel" type="PanelContainer" parent="Center"]
|
[node name="Panel" type="PanelContainer" parent="Center"]
|
||||||
custom_minimum_size = Vector2(350, 250)
|
custom_minimum_size = Vector2(320, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_styles/panel = SubResource("PanelStyle")
|
theme_override_styles/panel = SubResource("PanelStyle")
|
||||||
|
|
||||||
[node name="Contents" type="VBoxContainer" parent="Center/Panel"]
|
[node name="Contents" type="VBoxContainer" parent="Center/Panel"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/separation = 12
|
theme_override_constants/separation = 7
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Center/Panel/Contents"]
|
[node name="Title" type="Label" parent="Center/Panel/Contents"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_colors/font_color = Color(0.47, 0.91, 0.74, 1)
|
theme_override_colors/font_color = Color(0.47, 0.91, 0.74, 1)
|
||||||
theme_override_font_sizes/font_size = 17
|
theme_override_font_sizes/font_size = 13
|
||||||
text = "USŁUGI TUBYLCÓW"
|
text = "USŁUGI TUBYLCÓW"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const DATA := {
|
|||||||
"tactical_maneuver": {"name": "Manewr taktyczny", "active": true, "values": [0.30, 0.60, 1.00], "color": "b9a0ef"},
|
"tactical_maneuver": {"name": "Manewr taktyczny", "active": true, "values": [0.30, 0.60, 1.00], "color": "b9a0ef"},
|
||||||
"efficient_magazine": {"name": "Oszczędny magazynek", "active": false, "values": [0.10, 0.20, 0.50], "color": "a9d69a"},
|
"efficient_magazine": {"name": "Oszczędny magazynek", "active": false, "values": [0.10, 0.20, 0.50], "color": "a9d69a"},
|
||||||
"miner": {"name": "Górnik", "active": false, "values": [3, 6, 10], "color": "e5ac76"},
|
"miner": {"name": "Górnik", "active": false, "values": [3, 6, 10], "color": "e5ac76"},
|
||||||
"power_redirect": {"name": "Przekierowanie zasilania", "active": true, "values": [0.50, 0.90, 1.50], "color": "f28b6e"},
|
"power_redirect": {"name": "Przekierowanie zasilania", "active": true, "values": [1.00, 1.80, 3.00], "color": "f28b6e"},
|
||||||
}
|
}
|
||||||
|
|
||||||
static func value(skill: String, rank: int) -> float:
|
static func value(skill: String, rank: int) -> float:
|
||||||
@ -22,7 +22,7 @@ static func value(skill: String, rank: int) -> float:
|
|||||||
return float(DATA[skill]["values"][clampi(rank, 1, MAX_RANK) - 1])
|
return float(DATA[skill]["values"][clampi(rank, 1, MAX_RANK) - 1])
|
||||||
|
|
||||||
static func duration(skill: String) -> float:
|
static func duration(skill: String) -> float:
|
||||||
return 15.0 if skill == "reactor_overload" else DURATION
|
return 15.0 if skill == "reactor_overload" else (7.0 if skill == "power_redirect" else DURATION)
|
||||||
|
|
||||||
static func icon(skill: String) -> Texture2D:
|
static func icon(skill: String) -> Texture2D:
|
||||||
return load("res://assets/icons/captain/%s.png" % skill) as Texture2D
|
return load("res://assets/icons/captain/%s.png" % skill) as Texture2D
|
||||||
@ -47,5 +47,5 @@ static func description(skill: String, rank: int) -> String:
|
|||||||
"miner":
|
"miner":
|
||||||
return "+%d szt. surowca z każdej zniszczonej asteroidy." % roundi(value(skill, rank))
|
return "+%d szt. surowca z każdej zniszczonej asteroidy." % roundi(value(skill, rank))
|
||||||
"power_redirect":
|
"power_redirect":
|
||||||
return "Regeneracja energii +%d%% przez 5 sekund. Zużywa wszystkie tarcze i blokuje ich odzysk na czas działania. Wymaga min. 25%% tarcz." % amount
|
return "Regeneracja energii +%d%% przez 7 sekund. Zużywa wszystkie tarcze i blokuje ich odzysk na czas działania. Wymaga min. 25%% tarcz." % amount
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@ -42,9 +42,18 @@ var _weapon_timer := 0.0
|
|||||||
var _slow_remaining := 0.0
|
var _slow_remaining := 0.0
|
||||||
var _combat_target: Node2D
|
var _combat_target: Node2D
|
||||||
var virus_controlled := false
|
var virus_controlled := false
|
||||||
|
var _virus_infection_attempted := false
|
||||||
var _reward_claimed := false
|
var _reward_claimed := false
|
||||||
|
|
||||||
|
func roll_virus_infection() -> bool:
|
||||||
|
if loot_tier == 2 or _virus_infection_attempted:
|
||||||
|
return false
|
||||||
|
_virus_infection_attempted = true
|
||||||
|
return randf() < 0.5
|
||||||
|
|
||||||
func set_virus_controlled(value: bool) -> void:
|
func set_virus_controlled(value: bool) -> void:
|
||||||
|
if value and loot_tier == 2:
|
||||||
|
return
|
||||||
if virus_controlled == value or is_queued_for_deletion():
|
if virus_controlled == value or is_queued_for_deletion():
|
||||||
return
|
return
|
||||||
virus_controlled = value
|
virus_controlled = value
|
||||||
@ -246,9 +255,21 @@ func select_combat_target() -> Node2D:
|
|||||||
closest_distance = distance
|
closest_distance = distance
|
||||||
if closest != null:
|
if closest != null:
|
||||||
return closest
|
return closest
|
||||||
if is_instance_valid(_player) and not bool(_player.get("_is_destroyed")) and not bool(_player.call("is_cloaked")):
|
var player_visible := is_instance_valid(_player) and not bool(_player.get("_is_destroyed")) and not bool(_player.call("is_cloaked"))
|
||||||
|
var nearby_range := maxf(activation_range, weapon_range)
|
||||||
|
if player_visible and global_position.distance_to(_player.global_position) <= nearby_range:
|
||||||
return _player
|
return _player
|
||||||
return null
|
# Infected ships become fallback targets only when the player is absent nearby.
|
||||||
|
for ally in get_tree().get_nodes_in_group("virus_allies"):
|
||||||
|
if ally.is_queued_for_deletion() or float(ally.get("hull")) <= 0.0:
|
||||||
|
continue
|
||||||
|
var distance := global_position.distance_to(ally.global_position)
|
||||||
|
if distance <= nearby_range and distance < closest_distance:
|
||||||
|
closest = ally
|
||||||
|
closest_distance = distance
|
||||||
|
if closest != null:
|
||||||
|
return closest
|
||||||
|
return _player if player_visible else null
|
||||||
|
|
||||||
func apply_mine_hit() -> void:
|
func apply_mine_hit() -> void:
|
||||||
if is_queued_for_deletion() or hull <= 0.0:
|
if is_queued_for_deletion() or hull <= 0.0:
|
||||||
@ -341,7 +362,7 @@ func get_shot_damage() -> float:
|
|||||||
|
|
||||||
func get_weapon_dps() -> float:
|
func get_weapon_dps() -> float:
|
||||||
var interval := get_fire_interval()
|
var interval := get_fire_interval()
|
||||||
return get_shot_damage() / maxf(0.001, interval) * (1.0 + 0.25 * minf(3.0, interval) if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0)
|
return get_shot_damage() / maxf(0.001, interval) * (1.0 + 0.25 * minf(preload("res://scripts/game/radiation_status.gd").DURATION, interval) if weapon_kind == ItemDefinition.WeaponKind.GAMMA else 1.0)
|
||||||
|
|
||||||
func _reward_captain() -> void:
|
func _reward_captain() -> void:
|
||||||
if is_instance_valid(_player):
|
if is_instance_valid(_player):
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
const DURATION := 10.0
|
||||||
|
|
||||||
var remaining := 0.0
|
var remaining := 0.0
|
||||||
var tick_damage := 0.0
|
var tick_damage := 0.0
|
||||||
var credited_to_player := false
|
var credited_to_player := false
|
||||||
@ -16,7 +18,7 @@ static func apply(target: Node, damage_per_second: float, player_hit: bool) -> v
|
|||||||
status.set_script(load("res://scripts/game/radiation_status.gd"))
|
status.set_script(load("res://scripts/game/radiation_status.gd"))
|
||||||
status.name = "RadiationStatus"
|
status.name = "RadiationStatus"
|
||||||
target.add_child(status)
|
target.add_child(status)
|
||||||
status.remaining = 3.0
|
status.remaining = DURATION
|
||||||
status.tick_damage = maxf(status.tick_damage, damage_per_second)
|
status.tick_damage = maxf(status.tick_damage, damage_per_second)
|
||||||
status.credited_to_player = player_hit
|
status.credited_to_player = player_hit
|
||||||
|
|
||||||
|
|||||||
@ -199,6 +199,8 @@ func recycle_asteroid_fragment() -> void:
|
|||||||
_update_shield_visual()
|
_update_shield_visual()
|
||||||
|
|
||||||
func try_control_enemy(enemy: CharacterBody2D) -> bool:
|
func try_control_enemy(enemy: CharacterBody2D) -> bool:
|
||||||
|
if not is_instance_valid(enemy) or int(enemy.get("loot_tier")) == 2:
|
||||||
|
return false
|
||||||
var limit := int(get_passive_extension_value("virus"))
|
var limit := int(get_passive_extension_value("virus"))
|
||||||
if limit <= 0 or _is_destroyed:
|
if limit <= 0 or _is_destroyed:
|
||||||
return false
|
return false
|
||||||
@ -208,6 +210,8 @@ func try_control_enemy(enemy: CharacterBody2D) -> bool:
|
|||||||
controlled += 1
|
controlled += 1
|
||||||
if controlled >= limit:
|
if controlled >= limit:
|
||||||
return false
|
return false
|
||||||
|
if not bool(enemy.call("roll_virus_infection")):
|
||||||
|
return false
|
||||||
enemy.call("set_virus_controlled", true)
|
enemy.call("set_virus_controlled", true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ func get_passive_description() -> String:
|
|||||||
var value := get_passive_value()
|
var value := get_passive_value()
|
||||||
match definition.passive_effect:
|
match definition.passive_effect:
|
||||||
"recycler": return "Każdy zebrany odłamek asteroidy odnawia %.1f%% maksymalnych tarcz i energii." % value
|
"recycler": return "Każdy zebrany odłamek asteroidy odnawia %.1f%% maksymalnych tarcz i energii." % value
|
||||||
"virus": return "Przejmuje uciekających wrogów (poniżej 10%% kadłuba). Zamiast uciekać atakują swoich dawnych sojuszników. Wrogowie nie wybierają ich jako celu. Nadal możesz uszkodzić i zniszczyć je własną bronią. Limit jednocześnie kontrolowanych: %d." % int(value)
|
"virus": return "Ma 50%% szans na przejęcie uciekającego wroga (poniżej 10%% kadłuba). Jedna próba na statek; losowanie następuje, gdy jest wolne miejsce na przejęcie. Zamiast uciekać atakują swoich dawnych sojuszników. Bossowie są odporni na wirusa. Wrogowie atakują zawirusowane statki, gdy gracza nie ma w pobliżu. Nadal możesz uszkodzić i zniszczyć je własną bronią. Limit jednocześnie kontrolowanych: %d." % int(value)
|
||||||
"titanium_armor": return "Pochłania 50%% otrzymywanych obrażeń, gdy kadłub ma nie więcej niż %d%% maksimum. Próg sprawdzany przed trafieniem." % int(value)
|
"titanium_armor": return "Pochłania 50%% otrzymywanych obrażeń, gdy kadłub ma nie więcej niż %d%% maksimum. Próg sprawdzany przed trafieniem." % int(value)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
@ -446,6 +446,6 @@ func get_total_dps() -> float:
|
|||||||
for item in weapon_slots:
|
for item in weapon_slots:
|
||||||
var value := _weapon_dps(item, bonuses)
|
var value := _weapon_dps(item, bonuses)
|
||||||
if item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
if item != null and item.definition.weapon_kind == ItemDefinition.WeaponKind.GAMMA:
|
||||||
value *= 1.0 + 0.25 * minf(3.0, item.definition.fire_interval)
|
value *= 1.0 + 0.25 * minf(preload("res://scripts/game/radiation_status.gd").DURATION, item.definition.fire_interval)
|
||||||
total += value
|
total += value
|
||||||
return total
|
return total
|
||||||
|
|||||||
@ -2,6 +2,8 @@ extends Control
|
|||||||
|
|
||||||
signal next_level_requested
|
signal next_level_requested
|
||||||
|
|
||||||
|
const BUTTON_STYLE := preload("res://scripts/ui/hud_button_style.gd")
|
||||||
|
const CREDIT_ICON := preload("res://assets/icons/resources/credits.svg")
|
||||||
@onready var next_button: Button = $Center/Panel/Contents/NextButton
|
@onready var next_button: Button = $Center/Panel/Contents/NextButton
|
||||||
@onready var buy_ammunition_button: Button = $Center/Panel/Contents/BuyAmmunitionButton
|
@onready var buy_ammunition_button: Button = $Center/Panel/Contents/BuyAmmunitionButton
|
||||||
@onready var reset_skills_button: Button = $Center/Panel/Contents/ResetSkillsButton
|
@onready var reset_skills_button: Button = $Center/Panel/Contents/ResetSkillsButton
|
||||||
@ -13,32 +15,30 @@ var _inventory: ShipInventory
|
|||||||
var planet: Node2D
|
var planet: Node2D
|
||||||
var _open_tween: Tween
|
var _open_tween: Tween
|
||||||
var _missile_button: Button
|
var _missile_button: Button
|
||||||
|
|
||||||
var _gamma_buy: Button
|
var _gamma_buy: Button
|
||||||
|
var _stock_labels: Dictionary = {}
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
get_parent().get_node("FloatingWindows").call("register_window", self, panel, $Center/Panel/Contents/Title)
|
|
||||||
_gamma_buy = Button.new()
|
_gamma_buy = Button.new()
|
||||||
_gamma_buy.name = "BuyIrradiatedAmmunition"
|
_gamma_buy.name = "BuyIrradiatedAmmunition"
|
||||||
_gamma_buy.custom_minimum_size.y = 36
|
_missile_button = Button.new()
|
||||||
_gamma_buy.add_theme_font_size_override("font_size", 12)
|
_missile_button.name = "BuyMissile"
|
||||||
_gamma_buy.focus_mode = Control.FOCUS_NONE
|
var contents := $Center/Panel/Contents
|
||||||
$Center/Panel/Contents.add_child(_gamma_buy)
|
contents.add_child(_gamma_buy)
|
||||||
_gamma_buy.pressed.connect(func() -> void: _inventory.buy_irradiated_ammunition())
|
contents.add_child(_missile_button)
|
||||||
|
reset_skills_button.hide()
|
||||||
|
_build_compact_shop()
|
||||||
|
get_parent().get_node("FloatingWindows").call("register_window", self, panel, contents.get_node("Title"))
|
||||||
next_button.pressed.connect(func() -> void: next_level_requested.emit())
|
next_button.pressed.connect(func() -> void: next_level_requested.emit())
|
||||||
buy_ammunition_button.pressed.connect(_buy_ammunition)
|
buy_ammunition_button.pressed.connect(_buy_ammunition)
|
||||||
reset_skills_button.hide()
|
_gamma_buy.pressed.connect(func() -> void:
|
||||||
_missile_button = Button.new()
|
if visible and _inventory:
|
||||||
_missile_button.custom_minimum_size.y = 36
|
_inventory.buy_irradiated_ammunition()
|
||||||
_missile_button.add_theme_font_size_override("font_size", 12)
|
)
|
||||||
_missile_button.focus_mode = Control.FOCUS_NONE
|
|
||||||
_missile_button.tooltip_text = "Jedna sztuka amunicji rakietowej do dowolnej wyrzutni."
|
|
||||||
_missile_button.pressed.connect(func() -> void:
|
_missile_button.pressed.connect(func() -> void:
|
||||||
if visible and _inventory:
|
if visible and _inventory:
|
||||||
_inventory.buy_missile()
|
_inventory.buy_missile()
|
||||||
)
|
)
|
||||||
$Center/Panel/Contents.add_child(_missile_button)
|
|
||||||
$Center/Panel/Contents.move_child(_missile_button, reset_skills_button.get_index())
|
|
||||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
if _inventory:
|
if _inventory:
|
||||||
_inventory.ammunition_changed.connect(_refresh_ammunition_service)
|
_inventory.ammunition_changed.connect(_refresh_ammunition_service)
|
||||||
@ -46,11 +46,100 @@ func _ready() -> void:
|
|||||||
GameState.captain.changed.connect(_refresh_ammunition_service)
|
GameState.captain.changed.connect(_refresh_ammunition_service)
|
||||||
_refresh_ammunition_service()
|
_refresh_ammunition_service()
|
||||||
|
|
||||||
|
func _build_compact_shop() -> void:
|
||||||
|
var contents := $Center/Panel/Contents
|
||||||
|
contents.add_theme_constant_override("separation", 7)
|
||||||
|
status_label.add_theme_font_size_override("font_size", 10)
|
||||||
|
status_label.add_theme_color_override("font_color", Color("86b7aa"))
|
||||||
|
services_label.add_theme_font_size_override("font_size", 11)
|
||||||
|
services_label.add_theme_color_override("font_color", Color("efc982"))
|
||||||
|
services_label.size_flags_vertical = Control.SIZE_FILL
|
||||||
|
var wallet := HBoxContainer.new()
|
||||||
|
wallet.name = "Wallet"
|
||||||
|
wallet.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||||
|
wallet.add_theme_constant_override("separation", 6)
|
||||||
|
contents.add_child(wallet)
|
||||||
|
contents.move_child(wallet, 2)
|
||||||
|
var money_icon := TextureRect.new()
|
||||||
|
money_icon.texture = CREDIT_ICON
|
||||||
|
money_icon.custom_minimum_size = Vector2(15, 15)
|
||||||
|
money_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
money_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
money_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
wallet.add_child(money_icon)
|
||||||
|
services_label.reparent(wallet)
|
||||||
|
var offers := HBoxContainer.new()
|
||||||
|
offers.name = "Offers"
|
||||||
|
offers.add_theme_constant_override("separation", 6)
|
||||||
|
contents.add_child(offers)
|
||||||
|
contents.move_child(offers, 3)
|
||||||
|
_add_offer(offers, buy_ammunition_button, "ammunition", "Zwykła", 100, Color("e8b46f"))
|
||||||
|
_add_offer(offers, _gamma_buy, "irradiated_ammunition", "Radiacyjna", 10, Color("add580"))
|
||||||
|
_add_offer(offers, _missile_button, "missile", "Rakieta", 1, Color("82cddd"))
|
||||||
|
BUTTON_STYLE.apply(next_button, Color("78d7be"))
|
||||||
|
next_button.custom_minimum_size = Vector2(0, 34)
|
||||||
|
next_button.add_theme_font_size_override("font_size", 11)
|
||||||
|
next_button.icon = preload("res://assets/icons/extensions/teleport_art.png")
|
||||||
|
next_button.expand_icon = true
|
||||||
|
next_button.add_theme_constant_override("icon_max_width", 21)
|
||||||
|
contents.move_child(next_button, contents.get_child_count() - 1)
|
||||||
|
|
||||||
|
func _add_offer(offers: HBoxContainer, button: Button, item_id: String, caption: String, amount: int, accent: Color) -> void:
|
||||||
|
var card := PanelContainer.new()
|
||||||
|
card.name = item_id.capitalize().replace(" ", "") + "Offer"
|
||||||
|
card.custom_minimum_size.x = 94
|
||||||
|
card.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
style.bg_color = Color("101e2a")
|
||||||
|
style.border_color = accent.darkened(0.65)
|
||||||
|
style.set_border_width_all(1)
|
||||||
|
style.border_width_top = 2
|
||||||
|
style.set_corner_radius_all(6)
|
||||||
|
style.set_content_margin_all(6)
|
||||||
|
card.add_theme_stylebox_override("panel", style)
|
||||||
|
offers.add_child(card)
|
||||||
|
var column := VBoxContainer.new()
|
||||||
|
column.add_theme_constant_override("separation", 4)
|
||||||
|
card.add_child(column)
|
||||||
|
var icon := TextureRect.new()
|
||||||
|
icon.texture = load("res://assets/icons/resources/%s.png" % item_id)
|
||||||
|
icon.custom_minimum_size = Vector2(36, 36)
|
||||||
|
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
column.add_child(icon)
|
||||||
|
var title := Label.new()
|
||||||
|
title.text = "%s ×%d" % [caption, amount]
|
||||||
|
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
title.add_theme_font_size_override("font_size", 10)
|
||||||
|
title.add_theme_color_override("font_color", accent.lightened(0.2))
|
||||||
|
column.add_child(title)
|
||||||
|
var stock := Label.new()
|
||||||
|
stock.name = "Stock"
|
||||||
|
stock.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
stock.add_theme_font_size_override("font_size", 9)
|
||||||
|
stock.add_theme_color_override("font_color", Color("8ba4b7"))
|
||||||
|
column.add_child(stock)
|
||||||
|
_stock_labels[item_id] = stock
|
||||||
|
button.reparent(column)
|
||||||
|
BUTTON_STYLE.apply(button, accent)
|
||||||
|
button.custom_minimum_size = Vector2(0, 28)
|
||||||
|
button.add_theme_font_size_override("font_size", 10)
|
||||||
|
button.icon = CREDIT_ICON
|
||||||
|
button.expand_icon = true
|
||||||
|
button.add_theme_constant_override("icon_max_width", 12)
|
||||||
|
for state in ["normal", "hover", "pressed", "disabled"]:
|
||||||
|
var frame := button.get_theme_stylebox(state).duplicate() as StyleBoxFlat
|
||||||
|
frame.set_content_margin_all(4)
|
||||||
|
frame.set_corner_radius_all(4)
|
||||||
|
frame.shadow_size = 0
|
||||||
|
button.add_theme_stylebox_override(state, frame)
|
||||||
|
|
||||||
func show_services(at_level_cap: bool, portal_open: bool = false) -> void:
|
func show_services(at_level_cap: bool, portal_open: bool = false) -> void:
|
||||||
_refresh_ammunition_service()
|
_refresh_ammunition_service()
|
||||||
next_button.disabled = at_level_cap or portal_open
|
next_button.disabled = at_level_cap or portal_open
|
||||||
next_button.text = "OSIĄGNIĘTO OSTATNI UKŁAD" if at_level_cap else ("WORMHOLE OTWARTY" if portal_open else "IDŹ DO NASTĘPNEGO POZIOMU")
|
next_button.text = "OSTATNI UKŁAD" if at_level_cap else ("WORMHOLE OTWARTY" if portal_open else "OTWÓRZ WORMHOLE")
|
||||||
status_label.text = "Wleć w wormhole, aby przejść dalej." if portal_open else "Układ bezpieczny. Usługi dostępne."
|
status_label.text = "Wleć w wormhole, aby przejść dalej." if portal_open else "Bezpieczny układ · zaopatrzenie"
|
||||||
if visible:
|
if visible:
|
||||||
return
|
return
|
||||||
show()
|
show()
|
||||||
@ -81,30 +170,31 @@ func _position_at_planet() -> void:
|
|||||||
size = panel.get_combined_minimum_size()
|
size = panel.get_combined_minimum_size()
|
||||||
var viewport_size := get_viewport_rect().size
|
var viewport_size := get_viewport_rect().size
|
||||||
var sidebar := get_parent().get_node_or_null("ShipDrawer") as Control
|
var sidebar := get_parent().get_node_or_null("ShipDrawer") as Control
|
||||||
var screen_right := viewport_size.x - (sidebar.size.x + 8.0 if sidebar != null and sidebar.visible else 8.0)
|
var screen_right := minf(viewport_size.x - 8.0, sidebar.get_global_rect().position.x - 8.0) if sidebar != null and sidebar.visible else viewport_size.x - 8.0
|
||||||
var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5)
|
var target := planet_screen + Vector2(planet_radius + 24.0, -size.y * 0.5)
|
||||||
if target.x + size.x > screen_right:
|
if target.x + size.x > screen_right:
|
||||||
target.x = planet_screen.x - planet_radius - 24.0 - size.x
|
target.x = planet_screen.x - planet_radius - 24.0 - size.x
|
||||||
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 150.0)))
|
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 150.0)))
|
||||||
|
|
||||||
func _refresh_ammunition_service() -> void:
|
func _refresh_ammunition_service() -> void:
|
||||||
if _gamma_buy != null:
|
var ordinary_cost := _inventory.get_ammunition_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level))
|
||||||
_gamma_buy.text = "KUP 10 NAPROMIENIOWANEJ — %d KREDYTÓW" % (_inventory.get_irradiated_ammunition_buy_cost() if _inventory else ShipInventory.IRRADIATED_AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level))
|
var gamma_cost := _inventory.get_irradiated_ammunition_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.IRRADIATED_AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level))
|
||||||
|
var missile_cost := _inventory.get_missile_buy_cost() if _inventory else GameState.captain.discounted_price(ShipInventory.MISSILE_BUY_BASE_COST * maxi(1, GameState.system_level))
|
||||||
|
buy_ammunition_button.text = "KUP %d" % ordinary_cost
|
||||||
|
_gamma_buy.text = "KUP %d" % gamma_cost
|
||||||
|
_missile_button.text = "KUP %d" % missile_cost
|
||||||
|
buy_ammunition_button.disabled = _inventory == null or not _inventory.can_buy_ammunition()
|
||||||
_gamma_buy.disabled = _inventory == null or not _inventory.can_buy_irradiated_ammunition()
|
_gamma_buy.disabled = _inventory == null or not _inventory.can_buy_irradiated_ammunition()
|
||||||
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
||||||
_missile_button.text = "KUP +1 RAKIETĘ — %d KREDYTÓW" % (_inventory.get_missile_buy_cost() if _inventory else ShipInventory.MISSILE_BUY_BASE_COST)
|
buy_ammunition_button.tooltip_text = "Kup 100 zwykłych pocisków za %d kredytów." % ordinary_cost
|
||||||
reset_skills_button.disabled = not GameState.captain.can_reset_skills()
|
_gamma_buy.tooltip_text = "Kup 10 pocisków radiacyjnych za %d kredytów." % gamma_cost
|
||||||
reset_skills_button.text = "RESET SKILLI — %d KREDYTÓW" % GameState.captain.get_skill_reset_cost()
|
_missile_button.tooltip_text = "Kup 1 rakietę za %d kredytów." % missile_cost
|
||||||
reset_skills_button.tooltip_text = "Zwraca wszystkie %d wydanych punktów nauki. Koszt: 100 kredytów × poziom kapitana." % GameState.captain.get_spent_learning_points()
|
var discount := roundi(GameState.captain.get_skill_bonus("business_shark") * 100)
|
||||||
buy_ammunition_button.disabled = _inventory == null or not _inventory.can_buy_ammunition()
|
services_label.text = "%d kredytów%s" % [GameState.captain.credits, " · rabat %d%%" % discount if discount > 0 else ""]
|
||||||
if _inventory:
|
_stock_labels["ammunition"].text = "Zapas: %d" % (_inventory.ammunition if _inventory else 0)
|
||||||
buy_ammunition_button.text = "KUP %d AMUNICJI — %d KREDYTÓW" % [ShipInventory.AMMUNITION_BUY_AMOUNT, _inventory.get_ammunition_buy_cost()]
|
_stock_labels["irradiated_ammunition"].text = "Zapas: %d" % (_inventory.irradiated_ammunition if _inventory else 0)
|
||||||
services_label.text = "Amunicja: %d • Kredyty: %d\nRekin biznesu: −%d%% ceny zakupów" % [_inventory.ammunition, GameState.captain.credits, roundi(GameState.captain.get_skill_bonus("business_shark") * 100)]
|
_stock_labels["missile"].text = "Zapas: %d" % (_inventory.missile_ammunition if _inventory else 0)
|
||||||
|
|
||||||
func _buy_ammunition() -> void:
|
func _buy_ammunition() -> void:
|
||||||
if visible and _inventory:
|
if visible and _inventory:
|
||||||
_inventory.buy_ammunition()
|
_inventory.buy_ammunition()
|
||||||
|
|
||||||
func _reset_skills() -> void:
|
|
||||||
if visible:
|
|
||||||
GameState.captain.reset_skills()
|
|
||||||
|
|||||||
@ -27,6 +27,14 @@ func enemy_at(point: Vector2) -> CharacterBody2D:
|
|||||||
enemy.set("_weapon_timer", 100.0)
|
enemy.set("_weapon_timer", 100.0)
|
||||||
return enemy
|
return enemy
|
||||||
|
|
||||||
|
func seed_successful_infection() -> void:
|
||||||
|
for value in 100:
|
||||||
|
seed(value)
|
||||||
|
if randf() < 0.5:
|
||||||
|
seed(value)
|
||||||
|
return
|
||||||
|
assert(false)
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
GameState.start_new_run()
|
GameState.start_new_run()
|
||||||
@ -108,6 +116,7 @@ func _ready() -> void:
|
|||||||
var third := enemy_at(Vector2(450, 0))
|
var third := enemy_at(Vector2(450, 0))
|
||||||
first.hull = 1
|
first.hull = 1
|
||||||
second.hull = 1
|
second.hull = 1
|
||||||
|
seed_successful_infection()
|
||||||
first.call("_physics_process", 0.01)
|
first.call("_physics_process", 0.01)
|
||||||
second.call("_physics_process", 0.01)
|
second.call("_physics_process", 0.01)
|
||||||
assert(first.virus_controlled and not second.virus_controlled)
|
assert(first.virus_controlled and not second.virus_controlled)
|
||||||
@ -135,6 +144,7 @@ func _ready() -> void:
|
|||||||
assert(ship.shields == player_shields)
|
assert(ship.shields == player_shields)
|
||||||
# Increased capacity takes another ship; downgrade and unequip release extras.
|
# Increased capacity takes another ship; downgrade and unequip release extras.
|
||||||
virus.passive_value = 2
|
virus.passive_value = 2
|
||||||
|
seed_successful_infection()
|
||||||
second.call("_physics_process", 0.01)
|
second.call("_physics_process", 0.01)
|
||||||
assert(second.virus_controlled)
|
assert(second.virus_controlled)
|
||||||
virus.passive_value = 1
|
virus.passive_value = 1
|
||||||
|
|||||||
23
tests/abilities/virus_chance_test.gd
Normal file
23
tests/abilities/virus_chance_test.gd
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
extends Node
|
||||||
|
func _ready() -> void:
|
||||||
|
var script := preload("res://scripts/game/enemy_ship.gd")
|
||||||
|
seed(20261017)
|
||||||
|
var successes := 0
|
||||||
|
var failures := 0
|
||||||
|
for index in 2000:
|
||||||
|
var enemy := script.new()
|
||||||
|
var won: bool = enemy.roll_virus_infection()
|
||||||
|
successes += int(won)
|
||||||
|
failures += int(not won)
|
||||||
|
assert(not enemy.roll_virus_infection(), "A second frame must never reroll infection")
|
||||||
|
assert(not enemy.roll_virus_infection(), "Failed rolls must remain failed")
|
||||||
|
enemy.free()
|
||||||
|
assert(successes >= 900 and successes <= 1100)
|
||||||
|
assert(failures > 0 and successes > 0)
|
||||||
|
var boss := script.new()
|
||||||
|
boss.loot_tier = 2
|
||||||
|
for index in 100:
|
||||||
|
assert(not boss.roll_virus_infection())
|
||||||
|
boss.free()
|
||||||
|
print("VIRUS_CHANCE_TEST: PASS ", successes, "/2000 first attempts, no rerolls, bosses immune")
|
||||||
|
get_tree().quit()
|
||||||
1
tests/abilities/virus_chance_test.gd.uid
Normal file
1
tests/abilities/virus_chance_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dt8b1tr1i5dfu
|
||||||
4
tests/abilities/virus_chance_test.tscn
Normal file
4
tests/abilities/virus_chance_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/abilities/virus_chance_test.gd" id="1"]
|
||||||
|
[node name="VirusChanceTest" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
@ -25,6 +25,17 @@ func _ready() -> void:
|
|||||||
infected.shields = infected.max_shields
|
infected.shields = infected.max_shields
|
||||||
assert(hostile.select_combat_target() == ship)
|
assert(hostile.select_combat_target() == ship)
|
||||||
assert(infected.select_combat_target() == hostile)
|
assert(infected.select_combat_target() == hostile)
|
||||||
|
ship.position = Vector2(-2000, 0)
|
||||||
|
assert(hostile.select_combat_target() == infected)
|
||||||
|
ship.position = Vector2.ZERO
|
||||||
|
assert(hostile.select_combat_target() == ship)
|
||||||
|
var boss := make_enemy(Vector2(4000, 0))
|
||||||
|
boss.apply_level_settings(1, 2)
|
||||||
|
boss.hull = 1.0
|
||||||
|
assert(not ship.try_control_enemy(boss))
|
||||||
|
boss.set_virus_controlled(true)
|
||||||
|
assert(not boss.virus_controlled and boss.is_in_group("enemies"))
|
||||||
|
boss.queue_free()
|
||||||
var xp_after_conversion := GameState.captain.experience
|
var xp_after_conversion := GameState.captain.experience
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
|
|||||||
@ -19,5 +19,21 @@ func _ready() -> void:
|
|||||||
captain.tick_skills(0.11)
|
captain.tick_skills(0.11)
|
||||||
assert(not captain.is_skill_active("reactor_overload"))
|
assert(not captain.is_skill_active("reactor_overload"))
|
||||||
assert(preload("res://scripts/captain/captain_skills.gd").description("reactor_overload", 1).contains("15 sekund"))
|
assert(preload("res://scripts/captain/captain_skills.gd").description("reactor_overload", 1).contains("15 sekund"))
|
||||||
print("REACTOR_DURATION_TEST: PASS 15 seconds, 30-second cooldown, other skills still 5 seconds")
|
for rank in range(1, 4):
|
||||||
|
captain.skill_cooldowns.clear()
|
||||||
|
captain.skills["power_redirect"] = rank
|
||||||
|
assert(captain.equip_skill(2, "power_redirect"))
|
||||||
|
ship.shields = ship.max_shields
|
||||||
|
assert(captain.activate_skill("power_redirect", ship))
|
||||||
|
assert(ship.shields == 0.0)
|
||||||
|
assert(captain.skill_durations.power_redirect == 7.0)
|
||||||
|
assert(captain.skill_cooldowns.power_redirect == 30.0)
|
||||||
|
assert(is_equal_approx(captain.energy_regeneration_multiplier(), 1.0 + [1.0, 1.8, 3.0][rank - 1]))
|
||||||
|
captain.tick_skills(6.99)
|
||||||
|
assert(captain.is_skill_active("power_redirect"))
|
||||||
|
captain.tick_skills(0.02)
|
||||||
|
assert(not captain.is_skill_active("power_redirect"))
|
||||||
|
assert(is_equal_approx(captain.energy_regeneration_multiplier(), 1.0))
|
||||||
|
assert(preload("res://scripts/captain/captain_skills.gd").description("power_redirect", 3).contains("7 sekund"))
|
||||||
|
print("REACTOR_DURATION_TEST: PASS overload 15s, redirection 7s at +100/180/300%, 30s cooldown, tactical maneuver 5s")
|
||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
|
|||||||
1
tests/captain/reactor_duration_test.gd.uid
Normal file
1
tests/captain/reactor_duration_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bsqjxui01uk7c
|
||||||
@ -69,9 +69,9 @@ func _ready() -> void:
|
|||||||
assert(is_equal_approx(enemy.hull, 76))
|
assert(is_equal_approx(enemy.hull, 76))
|
||||||
var status: Node = enemy.get_node("RadiationStatus")
|
var status: Node = enemy.get_node("RadiationStatus")
|
||||||
status.set_physics_process(false)
|
status.set_physics_process(false)
|
||||||
for index in 6:
|
for index in 20:
|
||||||
status._physics_process(0.5)
|
status._physics_process(0.5)
|
||||||
assert(is_equal_approx(enemy.hull, 70))
|
assert(is_equal_approx(enemy.hull, 56))
|
||||||
assert(is_equal_approx(status.remaining, 0))
|
assert(is_equal_approx(status.remaining, 0))
|
||||||
assert(enemy.get_node("Sprite2D").modulate == Color.WHITE)
|
assert(enemy.get_node("Sprite2D").modulate == Color.WHITE)
|
||||||
for kind in 5:
|
for kind in 5:
|
||||||
|
|||||||
30
tests/items/radiation_duration_test.gd
Normal file
30
tests/items/radiation_duration_test.gd
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
extends Node
|
||||||
|
const RADIATION = preload("res://scripts/game/radiation_status.gd")
|
||||||
|
class Target:
|
||||||
|
extends CharacterBody2D
|
||||||
|
var total_damage := 0.0
|
||||||
|
func take_damage(amount: float, _critical: bool, _kind: int) -> void:
|
||||||
|
total_damage += amount
|
||||||
|
func take_weapon_hit(amount: float, critical: bool, kind: int) -> void:
|
||||||
|
take_damage(amount, critical, kind)
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
var target := Target.new()
|
||||||
|
add_child(target)
|
||||||
|
RADIATION.apply(target, 2.0, true)
|
||||||
|
var status := target.get_node("RadiationStatus")
|
||||||
|
status.set_physics_process(false)
|
||||||
|
assert(status.remaining == 10.0)
|
||||||
|
for index in 6:
|
||||||
|
status._physics_process(0.5)
|
||||||
|
assert(status.remaining == 7.0 and target.total_damage == 6.0)
|
||||||
|
RADIATION.apply(target, 1.0, true)
|
||||||
|
assert(status.remaining == 10.0 and status.tick_damage == 2.0)
|
||||||
|
for index in 20:
|
||||||
|
status._physics_process(0.5)
|
||||||
|
assert(status.remaining == 0.0 and target.total_damage == 26.0)
|
||||||
|
status._physics_process(1.0)
|
||||||
|
assert(target.total_damage == 26.0)
|
||||||
|
assert(preload("res://resources/items/gamma_cannon.tres").description.contains("10 s"))
|
||||||
|
print("RADIATION_DURATION_TEST: PASS 10s damage, refreshed timer, unchanged per-second damage, expiry and description")
|
||||||
|
get_tree().quit()
|
||||||
1
tests/items/radiation_duration_test.gd.uid
Normal file
1
tests/items/radiation_duration_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://rvxal1pmjjel
|
||||||
4
tests/items/radiation_duration_test.tscn
Normal file
4
tests/items/radiation_duration_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/items/radiation_duration_test.gd" id="1"]
|
||||||
|
[node name="RadiationDurationTest" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
44
tests/previews/planet_services_preview.gd
Normal file
44
tests/previews/planet_services_preview.gd
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
extends "res://scripts/game/game.gd"
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
super._ready()
|
||||||
|
set_physics_process(false)
|
||||||
|
player.set_physics_process(false)
|
||||||
|
player.get_node("WeaponController").set_physics_process(false)
|
||||||
|
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||||
|
enemy.set_physics_process(false)
|
||||||
|
player.position = protected_planet.position + Vector2(float(protected_planet.get("radius")) + 110.0, 0)
|
||||||
|
player.reset_physics_interpolation()
|
||||||
|
GameState.captain.credits = 2500
|
||||||
|
GameState.captain.skills["business_shark"] = 2
|
||||||
|
var inventory := player.get_node("ShipInventory") as ShipInventory
|
||||||
|
inventory.ammunition = 240
|
||||||
|
inventory.irradiated_ammunition = 12
|
||||||
|
inventory.missile_ammunition = 7
|
||||||
|
services_menu.show_services(false)
|
||||||
|
await get_tree().create_timer(0.5).timeout
|
||||||
|
assert(services_menu.get("panel").size.x <= 340.0)
|
||||||
|
assert(services_menu.get("panel").size.y <= 290.0)
|
||||||
|
if "--capture-preview" in OS.get_cmdline_user_args():
|
||||||
|
await RenderingServer.frame_post_draw
|
||||||
|
get_viewport().get_texture().get_image().save_png("res://artifacts/planet_services_preview.png")
|
||||||
|
print("PLANET_SERVICES_PREVIEW: captured ", services_menu.get("panel").size)
|
||||||
|
var credits := GameState.captain.credits
|
||||||
|
var cost := inventory.get_ammunition_buy_cost()
|
||||||
|
services_menu.get("buy_ammunition_button").pressed.emit()
|
||||||
|
assert(inventory.ammunition == 340 and GameState.captain.credits == credits - cost)
|
||||||
|
credits = GameState.captain.credits
|
||||||
|
cost = inventory.get_irradiated_ammunition_buy_cost()
|
||||||
|
services_menu.get("_gamma_buy").pressed.emit()
|
||||||
|
assert(inventory.irradiated_ammunition == 22 and GameState.captain.credits == credits - cost)
|
||||||
|
credits = GameState.captain.credits
|
||||||
|
cost = inventory.get_missile_buy_cost()
|
||||||
|
services_menu.get("_missile_button").pressed.emit()
|
||||||
|
assert(inventory.missile_ammunition == 8 and GameState.captain.credits == credits - cost)
|
||||||
|
GameState.captain.credits = 0
|
||||||
|
GameState.captain.emit_changed()
|
||||||
|
assert(services_menu.get("buy_ammunition_button").disabled and services_menu.get("_gamma_buy").disabled and services_menu.get("_missile_button").disabled)
|
||||||
|
services_menu.show_services(false, true)
|
||||||
|
assert(services_menu.get("next_button").disabled)
|
||||||
|
print("PLANET_SERVICES_TEST: PASS compact dimensions, all purchases, discounts, stock refresh, insufficient credits and portal state")
|
||||||
|
get_tree().quit()
|
||||||
1
tests/previews/planet_services_preview.gd.uid
Normal file
1
tests/previews/planet_services_preview.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://cmfun1xppkec8
|
||||||
5
tests/previews/planet_services_preview.tscn
Normal file
5
tests/previews/planet_services_preview.tscn
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[gd_scene load_steps=3 format=3]
|
||||||
|
[ext_resource type="PackedScene" path="res://scenes/game/game.tscn" id="1"]
|
||||||
|
[ext_resource type="Script" path="res://tests/previews/planet_services_preview.gd" id="2"]
|
||||||
|
[node name="PlanetServicesPreview" instance=ExtResource("1")]
|
||||||
|
script = ExtResource("2")
|
||||||
Loading…
x
Reference in New Issue
Block a user