extends SceneTree
## GATE — sizes and scales have no ceiling (hyper-games #109, 2026-10-12: "scale is
## currently bounded, should be unbounded" · "when creating arches, unit scale is blocked
## at 32").
##
## The create tool (box / stairs / arch) clamped size to 32 grid steps and height to 64;
## the scale tool clamped a model to ×100 and the model's Scale prop to 100. The FLOORS
## stay (a size of at least one step, a scale above zero); the ceilings go. The Object
## panel's slider keeps its 0.01–100 drag range — a ceiling there is a UI range, not a
## limit on the value (`open_max`).
##
## U1 the create tool takes size 100 and height 200; its settings declare no max
## U2 the floors stay: size 0 -> 1
## U3 a model at Scale 80, scaled ×2 with the tool, becomes 160 (was capped at 100)
## U4 the Scale prop keeps 500 through sanitize; 0.001 still rises to 0.01
##
## RUN: CI=true HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$GODOT" --headless --path . --script res://scenes/test/gate_unbounded_scale.gd
var _frame := 0
var _map: Node = null
var fails := 0
var checks := 0
func _p(c: bool, m: String, got: Variant = "") -> void:
checks += 1
if not c:
fails += 1
print(" %-66s %s %s" % [m, "OK" if c else "**FAIL**", str(got)])
func _key(code: int) -> InputEventKey:
var e := InputEventKey.new()
e.physical_keycode = code
e.keycode = code
e.pressed = true
return e
func _process(_d: float) -> bool:
_frame += 1
if _frame == 1:
root.get_node("/root/GameMode").set_mode("build")
var keet: Node = root.get_node_or_null("/root/KeetService")
if keet != null:
keet.current_member_id = "gate-author"
var gs: Node = root.get_node_or_null("/root/GameState")
if gs != null:
gs.route("world:level:*", 1, "peer")
_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
root.add_child(_map)
return false
if _frame < 30:
return false
_run()
if checks < 8:
print(" **FAIL** only %d checks ran -- setup died before the assertions" % checks)
fails += 1
print("\nGATE unbounded_scale: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
quit(0 if fails == 0 else 1)
return true
func _setting(op: Object, sid: String) -> Dictionary:
for d: Dictionary in (op.tool_settings() as Array):
if String(d.get("id", "")) == sid:
return d
return {}
func _run() -> void:
# ---- U1 / U2: the create tool ----
var bx: CreateBoxOperator = _map.get("_box")
bx.set_tool_setting("size", 100)
_p(int(bx.get("_size_steps")) == 100, "U1 size 100 grid steps is kept", bx.get("_size_steps"))
bx.set_tool_setting("height", 200)
_p(int(bx.get("_height_steps")) == 200, "U1 height 200 grid steps is kept", bx.get("_height_steps"))
_p(not _setting(bx, "size").has("max") and not _setting(bx, "height").has("max"),
"U1 the size/height settings declare no max", "%s / %s" % [_setting(bx, "size").get("max"), _setting(bx, "height").get("max")])
bx.set_tool_setting("size", 0)
_p(int(bx.get("_size_steps")) == 1, "U2 size 0 still rises to 1", bx.get("_size_steps"))
bx.set_tool_setting("size", 2)
bx.set_tool_setting("height", 2)
# ---- U3: the scale tool on a model ----
var md: String = _map.create_object("model", Transform3D(Basis(), Vector3(10, 0, 10)))
_map.set_object_props(md, {"scale": 80.0})
_map.select_object(md)
_map._unhandled_key_input(_key(KEY_S)) # scale is S since keymap step 3
var stack: Node = _map.call("_ensure_ops")
var op: Object = stack.active
if op is ScaleOperator:
# A model steps ×1.25 (the grid is a brush's; 2026-10-18): four steps from 80.
for i in 4:
_map._unhandled_key_input(_key(KEY_BRACKETRIGHT))
_p(is_equal_approx(float(op.object_factor()) * 80.0, 80.0 * pow(1.25, 4.0)), "U3 Scale 80 ×1.25⁴ -> 195.3 (was capped at 100)",
float(op.object_factor()) * 80.0)
stack.cancel() if stack.has_method("cancel") else stack.handle_escape()
else:
_p(false, "U3 S started the scale tool on the model", op)
# ---- U4: the prop ----
var spec: Dictionary = {}
for s: Dictionary in PrefabCatalogue.props_of("model", {}):
if String(s["id"]) == "scale":
spec = s
_p(float(PrefabCatalogue.sanitize(spec, 500.0)) == 500.0, "U4 Scale 500 survives sanitize", PrefabCatalogue.sanitize(spec, 500.0))
_p(is_equal_approx(float(PrefabCatalogue.sanitize(spec, 0.001)), 0.01), "U4 Scale 0.001 still rises to 0.01",
PrefabCatalogue.sanitize(spec, 0.001))
# ---- U5: the Object panel shows it ----
_map.set_object_props(md, {"scale": 160.0})
_map.select_object(md)
var panel: Node = _map.get("_object_panel")
var shown := -1.0
if panel != null:
panel.refresh()
var w: Variant = panel.widget("scale")
if w is HSlider:
shown = (w as HSlider).value
_p(is_equal_approx(shown, 160.0), "U5 the Object panel's Scale slider reads 160, not 100", shown)