diff --git a/artifacts/alien_research.png b/artifacts/alien_research.png index a2f4d6a..4ea2e4e 100644 Binary files a/artifacts/alien_research.png and b/artifacts/alien_research.png differ diff --git a/artifacts/alien_research_hover.png b/artifacts/alien_research_hover.png index ec2c814..7c2bdba 100644 Binary files a/artifacts/alien_research_hover.png and b/artifacts/alien_research_hover.png differ diff --git a/resources/effects/disabled_system_icon.gdshader b/resources/effects/disabled_system_icon.gdshader new file mode 100644 index 0000000..ee2a986 --- /dev/null +++ b/resources/effects/disabled_system_icon.gdshader @@ -0,0 +1,8 @@ +shader_type canvas_item; +render_mode unshaded; + +void fragment() { + vec4 pixel = texture(TEXTURE, UV); + float brightness = max(pixel.r, max(pixel.g, pixel.b)); + COLOR = vec4(vec3(1.0, 0.19, 0.16) * (0.7 + brightness * 0.3), pixel.a * smoothstep(0.03, 0.16, brightness)); +} diff --git a/scripts/game/enemy_health_bar.gd b/scripts/game/enemy_health_bar.gd index e81f8bc..caa267c 100644 --- a/scripts/game/enemy_health_bar.gd +++ b/scripts/game/enemy_health_bar.gd @@ -2,6 +2,8 @@ extends Node2D var enemy: CharacterBody2D var _tier_label: Label +var _disabled_icons: Array[PanelContainer] = [] +const DISABLED_ICONS := [preload("res://assets/icons/engine.png"),preload("res://assets/icons/plasma.png"),preload("res://assets/icons/shield.png")] func _ready() -> void: enemy = get_parent() as CharacterBody2D @@ -18,14 +20,56 @@ func _ready() -> void: _tier_label.add_theme_color_override("font_outline_color", Color("08111d")) _tier_label.add_theme_constant_override("outline_size", 3) add_child(_tier_label) + _build_disabled_icons() _update_position() _update_tier_label() + _update_disabled_icons() func _process(_delta: float) -> void: _update_position() _update_tier_label() + _update_disabled_icons() queue_redraw() +func _build_disabled_icons() -> void: + var material := ShaderMaterial.new() + material.shader = preload("res://resources/effects/disabled_system_icon.gdshader") + for system in 3: + var panel := PanelContainer.new() + panel.name = ["DisabledEngine","DisabledWeapon","DisabledShields"][system] + panel.mouse_filter = Control.MOUSE_FILTER_IGNORE + panel.size = Vector2(20,20) + panel.light_mask = 4 + var style := StyleBoxFlat.new() + style.bg_color = Color("17090be8") + style.border_color = Color("ff4b43") + style.set_border_width_all(1) + style.set_corner_radius_all(3) + style.set_content_margin_all(2) + panel.add_theme_stylebox_override("panel",style) + var icon := TextureRect.new() + icon.texture = DISABLED_ICONS[system] + icon.material = material + icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR + icon.mouse_filter = Control.MOUSE_FILTER_IGNORE + icon.light_mask = 4 + panel.add_child(icon) + add_child(panel) + _disabled_icons.append(panel) + +func _update_disabled_icons() -> void: + var active: Array[int] = [] + if enemy.hull > 0.0 and not enemy.is_queued_for_deletion(): + for system in 3: + if enemy.system_disabled(system): active.append(system) + for system in 3: + var panel := _disabled_icons[system] + panel.visible = system in active + if panel.visible: + panel.position = Vector2(-float(active.size()*22-2)*0.5+active.find(system)*22,-56) + func _update_position() -> void: global_position = enemy.global_position + Vector2(0, -enemy.get_visual_size() * 0.5 - 12.0) diff --git a/scripts/game/enemy_ship.gd b/scripts/game/enemy_ship.gd index 616a84e..b1cccdc 100644 --- a/scripts/game/enemy_ship.gd +++ b/scripts/game/enemy_ship.gd @@ -382,13 +382,8 @@ func disable_system(system: int) -> void: if system == 2 and not system_disabled(2): _offline_shields = shields shields = 0.0 - _disabled_systems[system] = 3.0 + _disabled_systems[system] = preload("res://scripts/planets/alien_research.gd").SYSTEM_DISABLE_DURATION if is_instance_valid(_shield_visual): _shield_visual.set_shield_values(shields,max_shields) - var popup := DAMAGE_POPUP_SCENE.instantiate() as Label - popup.text = "%s OFF · 3 s" % ["SILNIK","BROŃ","TARCZE"][system] - popup.set("text_color",Color("efa653")) - popup.position = position+Vector2(-30,-50) - get_parent().add_child(popup) func tick_disabled_systems(delta: float) -> void: var shields_offline := system_disabled(2) diff --git a/scripts/planets/alien_research.gd b/scripts/planets/alien_research.gd index 374f952..f1529db 100644 --- a/scripts/planets/alien_research.gd +++ b/scripts/planets/alien_research.gd @@ -1,6 +1,7 @@ extends RefCounted const ACTIVE_IDS := ["general", "weapons", "hull", "shields", "weapons_a", "weapons_a_next", "weapons_a_next_next", "weapons_a_next_next_next", "weapons_b", "weapons_b_next", "weapons_b_next_next", "weapons_b_next_next_next"] const BRANCHES := ["weapons", "hull", "shields"] +const SYSTEM_DISABLE_DURATION := 5.0 const TITLES := {"general":"Ogólna wiedza", "weapons":"Wiedza o broni", "hull":"Wiedza o kadłubie", "shields":"Wiedza o tarczach", "weapons_a":"Słaby punkt", "weapons_a_next":"Celny strzał", "weapons_a_next_next":"Rykoszet", "weapons_a_next_next_next":"Strzał w 10", "weapons_b":"Manewr wyprzedzający", "weapons_b_next":"System obrony przed obcymi", "weapons_b_next_next":"Dezorientacja celowania", "weapons_b_next_next_next":"Zakłócenia systemów obcych"} static func learned(id: String) -> bool: @@ -27,7 +28,7 @@ static func description(id: String) -> String: "hull": return "Twoja broń zadaje o 10% więcej obrażeń kadłubom obcych." "shields": return "Twoja broń zadaje o 10% więcej obrażeń tarczom obcych." "weapons_a": return "Każde bezpośrednie trafienie twojej broni zadaje obcym dodatkowe 5 obrażeń przed absorpcją." - "weapons_a_next": return "Każdy strzał ma 1% szansy wyłączyć na 3 sekundy losowy system obcego: silnik, broń lub tarcze. Obrażenia okresowe nie losują ponownie." + "weapons_a_next": return "Każdy strzał ma 1% szansy wyłączyć na 5 sekund losowy system obcego: silnik, broń lub tarcze. Czerwona ikona nad wrogiem wskazuje wyłączony system. Obrażenia okresowe nie losują ponownie." "weapons_a_next_next": return "Trafienie dowolną bronią razi też obcych do 10 px od obrysu trafionego statku. Promień eksplozji twoich rakiet rośnie o 10 px. Bez łańcuchowych rykoszetów." "weapons_a_next_next_next": return "Każde bezpośrednie trafienie zadaje pełne obrażenia jednocześnie tarczom i kadłubowi obcego. Nadal działa absorpcja." "weapons_b": return "Dodatkowe 5% szansy uniknięcia obrażeń od wrogich obcych. Łączy się niezależnie z pozostałymi unikami." diff --git a/scripts/planets/alien_research_tree.gd b/scripts/planets/alien_research_tree.gd index 178f80e..6d11c2f 100644 --- a/scripts/planets/alien_research_tree.gd +++ b/scripts/planets/alien_research_tree.gd @@ -4,12 +4,13 @@ const MENU := preload("res://scripts/planets/freighter_menu.gd") const COLORS := [Color("dfb775"), Color("e68c77"), Color("79cba8"), Color("7bc9e6")] const TILE_SIZE := Vector2(36,40) const PLACEHOLDER_LEVELS := 4 +const COST_COLUMN_WIDTH := 48.0 var progress: Resource var refreshed: Callable var points: Dictionary = {} func _ready() -> void: - custom_minimum_size = Vector2(290, 300) + custom_minimum_size = Vector2(330, 300) resized.connect(_build) _build() @@ -18,11 +19,18 @@ func _build() -> void: remove_child(child) child.queue_free() points.clear() - var width := maxf(290, size.x) - _add_skill("general", Vector2(width * 0.5, 24), COLORS[0]) + var width := maxf(330, size.x) + var tree_width := width-COST_COLUMN_WIDTH + _add_row_cost("general",24) + _add_row_cost("weapons",80) + var row_id := "weapons_a" + for level in PLACEHOLDER_LEVELS: + _add_row_cost(row_id,142+level*46) + row_id += "_next" + _add_skill("general", Vector2(COST_COLUMN_WIDTH+tree_width*0.5, 24), COLORS[0]) for i in range(3): var branch: String = DATA.BRANCHES[i] - var x := width * (float(i) + 0.5) / 3.0 + var x := COST_COLUMN_WIDTH+tree_width * (float(i) + 0.5) / 3.0 _add_skill(branch, Vector2(x, 80), COLORS[i + 1]) for path in ["a","b"]: var id: String = branch+"_"+path @@ -57,18 +65,32 @@ func _add_skill(id: String, center: Vector2, color: Color) -> void: var icon := TextureRect.new() icon.texture = load("res://assets/freighter/research/" + id + ".png") icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE - icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS icon.mouse_filter = Control.MOUSE_FILTER_IGNORE - icon.position = Vector2(5, 1) - icon.size = Vector2(26, 26) + icon.position = Vector2.ONE + icon.size = TILE_SIZE-Vector2(2,2) + icon.clip_contents = true if not unlocked: icon.modulate = Color(0.5, 0.55, 0.55, 0.65) button.add_child(icon) - var price := MENU.label(button, "✓" if learned else str(DATA.cost(id)), 12, color if unlocked else MENU.MUTED) - price.mouse_filter = Control.MOUSE_FILTER_IGNORE - price.position = Vector2(0, 27) - price.size = Vector2(36, 12) + if learned: + var check := MENU.label(button,"✓",12,color) + check.mouse_filter = Control.MOUSE_FILTER_IGNORE + check.position = TILE_SIZE-Vector2(13,15) + check.size = Vector2(12,12) + check.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + +func _add_row_cost(id: String, y: float) -> void: + var price := MENU.label(self,"%d pkt" % DATA.cost(id),12,MENU.MUTED) + price.name = "RowCost_%d" % DATA.cost(id) + price.autowrap_mode = TextServer.AUTOWRAP_OFF + price.position = Vector2(0,y-10) + price.size = Vector2(COST_COLUMN_WIDTH-6,20) + price.vertical_alignment = VERTICAL_ALIGNMENT_CENTER price.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + price.tooltip_text = "Koszt każdej technologii w tym rzędzie: %d próbek." % DATA.cost(id) + # The initially wrapped label may retain its old minimum height until text is shaped. + price.set_deferred("size",Vector2(COST_COLUMN_WIDTH-6,20)) func _add_placeholder(id: String, center: Vector2) -> void: points[id] = center diff --git a/tests/ships/alien_research_test.gd b/tests/ships/alien_research_test.gd index 0fde7d8..09fcf95 100644 --- a/tests/ships/alien_research_test.gd +++ b/tests/ships/alien_research_test.gd @@ -49,6 +49,8 @@ func _ready() -> void: assert(screen._drawer.size.x == 490 and screen._drawer.size.y == 430) var skill_buttons: Array[Node] = screen._content.find_children("*", "Button", true, false) assert(skill_buttons.size() == 28) + var tree: Control = skill_buttons[0].get_parent() + assert(is_equal_approx(tree.get_node("RowCost_10").get_global_rect().get_center().y,skill_buttons[0].get_global_rect().get_center().y)) assert(DATA.parent("weapons_a_next_next") == "weapons_a_next") assert(not DATA.purchase(progress,"weapons_a_next_next_next")) for button in skill_buttons: diff --git a/tests/ships/alien_weapon_technologies_test.gd b/tests/ships/alien_weapon_technologies_test.gd index 957f01c..68608da 100644 --- a/tests/ships/alien_weapon_technologies_test.gd +++ b/tests/ships/alien_weapon_technologies_test.gd @@ -70,18 +70,30 @@ func _ready() -> void: assert(target.system_disabled(2) and target.shields==0.0) target.regenerate_defenses(1.0) assert(target.shields==0.0) - target.tick_disabled_systems(3.1) + var health_bar: Node2D = target.get_node("HealthBar") + health_bar._process(0.0) + assert(health_bar.get_node("DisabledShields").visible) + assert(not health_bar.get_node("DisabledEngine").visible and not health_bar.get_node("DisabledWeapon").visible) + target.tick_disabled_systems(4.9) + assert(target.system_disabled(2),"System remains disabled for five seconds") + target.tick_disabled_systems(0.2) + health_bar._process(0.0) + assert(not health_bar.get_node("DisabledShields").visible) assert(not target.system_disabled(2) and target.shields==85.0) target.disable_system(1) var count := get_child_count() target._fire_plasma(Vector2.RIGHT) assert(get_child_count()==count,"Disabled weapons cannot fire") target.disable_system(0) + target.rotation = 1.2 + health_bar._process(0.0) + assert(health_bar.get_node("DisabledEngine").visible and health_bar.get_node("DisabledWeapon").visible) + assert(is_zero_approx(health_bar.global_rotation),"Status icons stay upright as the enemy turns") target.velocity = Vector2.ZERO target._activated = true target._physics_process(0.1) assert(target.velocity.is_zero_approx(),"Disabled engines cannot produce thrust") - target.tick_disabled_systems(3.1) + target.tick_disabled_systems(5.1) assert(not target.system_disabled(0) and not target.system_disabled(1)) reset_enemy(target,0.0) target.take_research_dot(10,DamageTypes.Type.RADIATION,0)