--- scripts/ui/ui_test.gd +++ scripts/ui/ui_test.gd @@ -182,6 +182,11 @@ static func run(main: Node) -> void: plus7 = true check(ws != null and eb.find_child("Slot_costume_weapon", true, false) != null and plus7, "slots around the preview, +7 refine badge") check(eb.find_child("Stats", true, false) != null, "stat summary") + await equip_toggle_clicks(main, hud) + EquipWindow.show_3d = true + hud.toggle("equip") + await frames(main, 6) + eb = hud.bodies["equip"] var r0: float = hero.rotation.y var mm := InputEventMouseMotion.new() mm.relative = Vector2(60, 0) @@ -337,4 +342,65 @@ static func _v2_skills(main: Node, hud) -> void: check(hud.ui_root.find_child("PadAwaken", true, false) != null, "HUD: transformation button on the skill pad") if is_instance_valid(m) and not m.dead: m.map.remove_mob(m) + # sticky tooltips (ui/hover_tip.gd) + shimmering skill icons + var ht = hud.get_meta("ui3_tip") if hud.has_meta("ui3_tip") else null + check(ht != null and hud.hot_buttons[0].has_meta("ui3_tip") and hud.hot_buttons[0].tooltip_text == "", "hotbar: sticky tooltip key, native tooltip off") + if ht: + var tip: Control = ht.build("skill:dc_shield_rush", null) + check(tip != null and tip.find_children("*", "Label", true, false).size() >= 3, "sticky skill tip: header + texts") + tip.free() + var st: Control = load("res://scripts/icons.gd").skill_tile("dc_shield_rush", 56.0) + check(st.find_child("Shimmer", true, false) != null, "skill icon tile carries the shimmer layer") + check(hud.hot_buttons.all(func(b): return b.get_node_or_null("CdSweep") != null), "every hotbar slot (pad + F5-F9 row) has the clock cooldown") + st.free() + + +## Clicks a control through real input events (motion + press + release at its centre, like a player) and +## returns the control the viewport reported under the mouse (for "an overlay eats the click" bugs). +static func real_click(main: Node, c: Control, churn: bool = false) -> Control: + var vp: Viewport = main.get_viewport() + var at: Vector2 = c.get_global_rect().get_center() + var mm := InputEventMouseMotion.new() + mm.position = at + mm.global_position = at + vp.push_input(mm, true) + await frames(main, 2) + var hov: Control = vp.gui_get_hovered_control() + for pressed in [true, false]: + if churn and not pressed: + # an HP / SP tick between mouse-down and mouse-up (combat, regen): the HUD refreshes its windows + PlayerState.changed.emit() + await frames(main, 2) + var mb := InputEventMouseButton.new() + mb.button_index = MOUSE_BUTTON_LEFT + mb.pressed = pressed + mb.position = at + mb.global_position = at + vp.push_input(mb, true) + await frames(main, 2) + return hov + + +## Equipment 2D <-> 3D switch by real clicks (owner bug 2026-09-30: the 3D button did nothing). +static func equip_toggle_clicks(main: Node, hud) -> void: + close_all(hud) + EquipWindow.show_3d = false + hud.toggle("equip") + await frames(main, 8) + var eb: Control = hud.bodies["equip"] + var b3: Button = eb.find_child("View3D", true, false) + check(b3 != null and not b3.disabled, "equip: 3D button present and enabled") + if b3 == null: + return + var hov: Control = await real_click(main, b3, true) + await frames(main, 6) + check(hov == b3, "equip: nothing covers the 3D button (under the mouse: %s)" % (str(hov.get_path()) if hov else "none")) + check(EquipWindow.show_3d and eb.find_child("Preview3D", true, false) != null, "equip: a real click on 3D shows the 3D hero (with an HP tick mid-click)") + var b2: Button = eb.find_child("View2D", true, false) + if b2: + var hov2: Control = await real_click(main, b2, true) + await frames(main, 6) + check(hov2 == b2 and not EquipWindow.show_3d and eb.find_child("Portrait", true, false) != null, + "equip: a real click on 2D brings the portrait back (under the mouse: %s)" % (str(hov2.get_path()) if hov2 else "none")) + close_all(hud)