extends SceneTree
## GATE — the Geiss maps are WORLDS like the mountain: the game's sky with a cloud bank,
## brushes, and terrain CSG (user 2026-10-06: "add a cloudshader and a proper world
## environment to geiss as well as the ability to build brushes and also to do csg
## edits on the terrain").
## E1 CSG: a left click (player.fire) with the mouse captured carves the terrain —
## through the REAL input chain. map_geiss overrode map_core's _unhandled_input
## without calling super, so the universal carve never ran on any Geiss map.
## E2 brushes: the map is a map_dc_level (brush store, brush editor, journal) with a
## DCLevel node
## E3 environment: under the game's shared sky (/root/Game/Sky3DExtended) the map
## owns NO WorldEnvironment or Sun of its own — a map-owned one makes game.gd
## detach the shared sky (day/night, Atmosphere panel)
## E4 clouds: a SunshineClouds effect is on the shared sky's compositor while the map
## is in, and gone after it leaves
## The shared sky is stood up here as the game builds it: a WorldEnvironment named
## Sky3DExtended under a node named Game, with SunLight / MoonLight children.
##
## ⚠ WINDOWED (the carve needs built collision):
## env -u CI HYPERTPS_DAEMON_TCP=127.0.0.1:1 DISPLAY=:0 "$HYPER_TPS_GODOT" --path . \
## --script res://scenes/test/gate_geiss_editable.gd [-- map_geiss_world]
const ProbeWindow := preload("res://scenes/test/probe_window.gd")
var ok := true
var checks := 0
var _ws := ""
var _name := ""
var _map: Node
var _sky: WorldEnvironment
var _f := 0
var _before := -1
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 _initialize() -> void:
var a := OS.get_cmdline_user_args()
_name = a[0] if a.size() > 0 else "map_geiss"
_ws = ProbeWindow.free_workspace()
var game := Node3D.new()
game.name = "Game"
root.add_child(game)
_sky = WorldEnvironment.new()
_sky.name = "Sky3DExtended"
_sky.environment = Environment.new()
game.add_child(_sky)
for l in ["SunLight", "MoonLight"]:
var dl := DirectionalLight3D.new()
dl.name = l
_sky.add_child(dl)
# map_geiss's surface is near y=0; the terrace maps derive their own camera start
# from the field (a fixed one can sit inside a 300 m terrace and see no surface).
# map_geiss_terraces' own start is an overview 600 m out — beyond the carve's
# 200 m reach — so it gets one just over its surface (measured 17.8 m at (0, 16)).
if _name == "map_geiss":
OS.set_environment("GEISS_CAM", "0,40,16,0,-60")
elif _name == "map_geiss_terraces":
OS.set_environment("GEISS_CAM", "0,60,70,0,-40") # 2x field: surface ~36 m at (0, 32)
elif _name == "map_geiss_world": # its own start is ~200 m up, at the carve's reach
OS.set_environment("GEISS_CAM", "0,75,70,0,-40") # 2x field: ground ~51 m at (0, 32)
_map = (load("res://scenes/maps/%s.tscn" % _name) as PackedScene).instantiate()
root.add_child(_map)
func _process(_d: float) -> bool:
if not ProbeWindow.drawing(root):
ProbeWindow.move_to(_ws, Vector2i(1600, 900))
_f += 1
if _f == 2:
# ---- E2 / E3 / E4: what the map did on entry ----
_p(_map.get_script() != null and _inherits(_map.get_script(), "res://scenes/maps/map_dc_level.gd"),
"E2 %s is a map_dc_level (brush store, editor, journal)" % _name)
_p(_map.get_node_or_null("DCLevel") != null, "E2 it has a DCLevel to build brushes in")
var own_env := 0
var own_sun := 0
for c in _map.get_children():
if c is WorldEnvironment: own_env += 1
if c is DirectionalLight3D: own_sun += 1
_p(own_env == 0 and own_sun == 0, "E3 under the shared sky the map owns no WorldEnvironment / Sun",
"%d env, %d sun" % [own_env, own_sun])
_p(_clouds_on_sky() > 0, "E4 a SunshineClouds effect is on the shared sky's compositor", _clouds_on_sky())
return false
if _f < 600: # stream ~10 s so the carve has collision under the crosshair
return false
var t: Array = _map.find_children("*", "DCTerrain", true, false)
if t.is_empty():
_p(false, "E1 the map has a DCTerrain")
return _finish()
if _f == 600:
_before = int(t[0].call("get_edit_count"))
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
var ev := InputEventMouseButton.new()
ev.button_index = MOUSE_BUTTON_LEFT
ev.pressed = true
ev.position = Vector2(root.size) * 0.5
ev.global_position = ev.position
Input.parse_input_event(ev)
var up := ev.duplicate() as InputEventMouseButton
up.pressed = false
Input.parse_input_event(up)
return false
if _f < 620:
return false
var after := int(t[0].call("get_edit_count"))
_p(after > _before, "E1 a left click with the mouse captured carves the terrain", "edits %d -> %d" % [_before, after])
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
# ---- E4: leaving takes the clouds with it ----
root.remove_child(_map)
_map.free()
_p(_clouds_on_sky() == 0, "E4 after the map leaves, its clouds are off the shared sky", _clouds_on_sky())
return _finish()
func _finish() -> bool:
print("\n%d checks — %s" % [checks, "PASS" if ok else "FAIL"])
quit(0 if ok else 1)
return true
func _clouds_on_sky() -> int:
if _sky.compositor == null:
return 0
var n := 0
for fx in _sky.compositor.compositor_effects:
if fx != null and fx.get_class() != "" and fx is SunshineCloudsGD:
n += 1
return n
func _inherits(s: Script, path: String) -> bool:
while s != null:
if s.resource_path == path:
return true
s = s.get_base_script()
return false