OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_bot_editor.gd

137 lines · gd ref:
extends SceneTree
## GATE — the Bot editor tab (user, 2026-10-04: "level editor / bot editor tabs").
##   T1  the top bar carries Level editor / Bot editor tabs; Level is the default
##   T2  the Bot editor tab switches the workspace: the Bots panel shows, the level
##       panels (Tools, Tool settings) hide, the shared ones (Object, Outliner) stay;
##       the bar's level-only parts (snap, Brush menu) hide
##   T3  "Place bot" places a bot with the chosen brain + body as ONE gesture, selects
##       it, and the panel lists it; selecting a list row selects that bot
##   T4  in the Bot editor brush keys do nothing (N = new box starts no operator)
##   T5  back to the Level editor restores the level panels and the box key
##
## Run: CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/gate_bot_editor.gd

var ok := true
var checks := 0
var _frame := 0
var _map: Node
var _dock: Node
var _step := 0
var _wait := 0
var _dot := ""


func _p(c: bool, m: String, got: Variant = "") -> void:
	checks += 1
	print(("ok   " if c else "FAIL: ") + m + ("" if str(got) == "" else "  (" + str(got) + ")"))
	if not c:
		ok = false


func _key(code: int) -> InputEventKey:
	var e := InputEventKey.new()
	e.physical_keycode = code
	e.keycode = code
	e.pressed = true
	return e


func _shown(id: String) -> bool:
	var rec: Dictionary = _dock._panels.get(id, {})
	if rec.is_empty():
		return false
	return ((rec["section"] as Control).get_parent() as Control).visible


func _process(_d: float) -> bool:
	_frame += 1
	if _frame == 1:
		_dock = root.get_node("/root/BuildDock")
		_dock.set_workspace("level")                 # pin; restored at the end
		_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
		root.add_child(_map)
		return false
	if _frame < 30:
		return false
	if _wait > 0:
		_wait -= 1
		return false
	_step += 1
	match _step:
		1: _t1_t2()
		2: _t3()
		3: _t3_list()
		4: _t4_t5()
		_:
			_dock.set_workspace("level")
			print("\n%d checks — %s" % [checks, "PASS" if ok else "FAIL"])
			quit(0 if ok else 1)
			return true
	_wait = 3
	return false


func _t1_t2() -> void:
	root.get_node("/root/GameMode").set_mode("build")
	var top: Node = _map.get("_top_bar")
	_p(top != null and top.workspace_tab("level") != null and top.workspace_tab("bot") != null, "T1 the top bar has both tabs")
	_p(_dock.workspace() == "level" and top.workspace_tab("level").button_pressed, "T1 Level editor is the default")
	_p(_shown("tools") and not _shown("bots"), "T1 level panels show, the Bots panel does not")
	top.workspace_tab("bot").emit_signal("pressed")
	_p(_dock.workspace() == "bot", "T2 the Bot editor tab switches the workspace", _dock.workspace())
	_p(_shown("bots"), "T2 the Bots panel shows")
	_p(not _shown("tools") and not _shown("toolsettings"), "T2 the level panels hide")
	_p(_shown("object") and _shown("outliner") and _shown("topbar"), "T2 the shared panels stay")
	_p(not (top.snap_button() as Control).visible, "T2 the bar's level-only controls hide")
	var brush_hidden := false
	var bar: MenuBar = top.get("_bar")
	for i in bar.get_menu_count():
		if bar.get_menu_title(i) == "Object":      # Blender's Object menu (was "Brush")
			brush_hidden = bar.is_menu_hidden(i)
	_p(brush_hidden, "T2 and the Object menu")
	_p(top.workspace_tab("bot").button_pressed and not top.workspace_tab("level").button_pressed, "T2 the tab shows which is active")


func _t3() -> void:
	var panel: Node = _map.get("_bot_panel")
	panel.get("_brain").select(BrainCatalogue.ids().find("patrol"))
	panel.get("_body").select(PrefabCatalogue.BOT_BODIES.find("hopper"))
	_dot = panel.place_selected()
	_p(_dot != "", "T3 Place bot placed one", _dot)
	var props: Dictionary = _map.object_props(_dot)
	_p(String(props.get("brain", "")) == "patrol" and String(props.get("body", "")) == "hopper",
		"T3 with the chosen brain and body", props)
	_p(String(_map.get("_sel_object")) == _dot, "T3 and it is selected (the Object panel edits it)")
	var g: Dictionary = _map.get("_persist").gestures()[0]
	_p(String(g["label"]) == "Add bot" and int(g["count"]) == 2, "T3 as one gesture", "%s / %d" % [g["label"], int(g["count"])])


func _t3_list() -> void:
	var panel: Node = _map.get("_bot_panel")
	panel.refresh()
	_p(panel.rows().has(_dot), "T3 the panel lists it", panel.rows())
	var other: String = _map.place_bot("pathwalker", "crawler")
	panel.refresh()
	var lst: ItemList = panel.get("_list")
	lst.deselect_all()
	lst.select(panel.rows().find(_dot))
	panel._apply_list_selection()
	_p(String(_map.get("_sel_object")) == _dot, "T3 selecting its row selects that bot", _map.get("_sel_object"))
	_p(other != "", "T3 (a second bot for the list)")


## A level-only key that needs NO aim (headless gates aim at nothing, so "new box"
## would prove nothing): 3 = face select mode. Ignored in the Bot editor, and — the
## control — honoured in the Level editor, so the check can fail for the right reason.
func _t4_t5() -> void:
	var before := String(_map.get("_sel_mode"))
	var want := "face" if before != "face" else "brush"
	var k := _key(KEY_3 if want == "face" else KEY_4)
	_map._unhandled_key_input(k)
	_p(String(_map.get("_sel_mode")) == before, "T4 in the Bot editor a brush key does nothing", _map.get("_sel_mode"))
	_dock.set_workspace("level")
	_p(_shown("tools") and not _shown("bots"), "T5 the Level editor restores its panels")
	_p(((_map.get("_top_bar")).snap_button() as Control).visible, "T5 and the bar's level controls")
	_map._unhandled_key_input(k)
	_p(String(_map.get("_sel_mode")) == want, "T5 and the same key works there (control)", _map.get("_sel_mode"))