extends Area2D # GLOBAL CFG @onready var fade_rect: ColorRect = get_node("../Fader/ColorRect") func fade_out(duration := 1.0): fade_rect.visible = true fade_rect.modulate.a = 0.0 var tween = get_tree().create_tween() tween.tween_property(fade_rect, "modulate:a", 1.0, duration) func fade_in(duration := 1.0): fade_rect.visible = true fade_rect.modulate.a = 1.0 var tween = get_tree().create_tween() tween.tween_property(fade_rect, "modulate:a", 0.0, duration) tween.tween_callback(Callable(self, "_on_fade_in_complete")) func wait(seconds: float) -> void: await get_tree().create_timer(seconds).timeout func _on_fade_in_complete(): fade_rect.visible = false const scalef = 3; const textsize = 16; func load_json(path: String): # stolen from reddit then updated to godot 4 lmao var file := FileAccess.open(path, FileAccess.READ) var content = file.get_as_text() file.close() var parsed_json = JSON.parse_string(content) return parsed_json func loadstring(path: String): # stolen from reddit then updated to godot 4 lmao var file := FileAccess.open(path, FileAccess.READ) var content = file.get_as_text() file.close() return content var rng = RandomNumberGenerator.new() # Called when the node enters the scene tree for the first time. func _ready() -> void: await fade_in(1.0) get_node("../Player").set_meta("can_walk",true) for child in get_children(): child.queue_free() var root = get_node("../") var world = load_json("res://worlds/"+self.get_meta("world")+".json"); if world.has("mapscript"): var script = loadstring("res://worlds/"+self.get_meta("world")+".lua") get_node("../LuaEnv").reset_env() get_node("../LuaEnv").run_script(script,self) var assetcfg = load_json("res://assetcfg.json") var texturespace = root.get_meta("resourcepack"); var worldassemble = {}; var plr = get_node("../Player") plr.position = Vector2(world["pspawn"]["w"]*(16*scalef),world["pspawn"]["h"]*(16*scalef)) for y in range(world["height"]+1): for x in range(world["width"]+1): if not worldassemble.has(y): worldassemble[y] = {} worldassemble[y][x] = {"thing":world["fill"],"action":"none"} for modifier in world["features"]: var x = int(modifier["w"]) var y = int(modifier["h"]) worldassemble[y][x] = modifier["t"] # assuming this script extends Node2D or Area2D that builds the world for y in range(worldassemble.size()): for x in range(worldassemble[y].size()): var along = worldassemble[y][x] var walpole = along["thing"] var cfg = assetcfg[walpole] # combine base data from cfg and instance-specific data from along var tile_type = along.get("action", cfg.get("action", "default")) var is_collidable = along.get("collidable", cfg.get("collidable", false)) var tex_path = "res://%s/text/%s" % [texturespace, cfg["textname"]] var tex = load(tex_path) # --- choose node type var tile_node: Node2D if tile_type == "tp": tile_node = Area2D.new() # teleporter elif is_collidable: tile_node = StaticBody2D.new() # solid else: tile_node = Area2D.new() # non-collidable sensor/decor add_child(tile_node) tile_node.position = Vector2(x * (scalef * textsize), y * (scalef * textsize)) tile_node.name = "tile_%s_%s" % [x, y] tile_node.set_meta("collidable", is_collidable) # --- sprite var sprite = Sprite2D.new() sprite.texture = tex sprite.scale = Vector2(scalef, scalef) tile_node.add_child(sprite) # optional random rotation if cfg.get("allowRandRot", false): sprite.rotation_degrees = 90 * rng.randi_range(0, 3) # --- collision shape for solids and sensors if is_collidable or tile_type == "tp": var col = CollisionShape2D.new() var shape = RectangleShape2D.new() shape.size = Vector2(16 * scalef, 16 * scalef) col.shape = shape col.position = Vector2.ZERO tile_node.add_child(col) # --- teleporter setup if tile_type == "tp": var target_world = along.get("target_world", cfg.get("target_world", "default")) tile_node.set_meta("world", target_world) tile_node.connect("body_entered", Callable(self, "_on_tp_entered").bind(tile_node)) _add_world_borders(world["width"], world["height"]) # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: pass func _on_tp_entered(body: Node, source: Node) -> void: if not body.is_in_group("player"): return print("Teleport triggered by:", body.name) await fade_out(1.0) get_node("../Player").set_meta("can_walk",false) await wait(1.0) if body.has_method("set_velocity"): body.set_velocity(Vector2.ZERO) if source.has_meta("world"): var new_world = source.get_meta("world") print("Teleporting to world:", new_world) set_meta("world", new_world) call_deferred("_ready") # safely rebuild else: print("⚠️ Teleporter node has no 'world' meta set!") func _add_world_borders(width: int, height: int) -> void: var border_thickness = 32.0 * scalef var w_px = width * (textsize * scalef) var h_px = height * (textsize * scalef) var positions = { "top": Vector2(w_px / 2, -border_thickness / 2), "bottom": Vector2(w_px / 2, h_px + border_thickness / 2), "left": Vector2(-border_thickness / 2, h_px / 2), "right": Vector2(w_px + border_thickness / 2, h_px / 2) } for name in positions.keys(): var wall = StaticBody2D.new() wall.name = "border_%s" % name var shape = RectangleShape2D.new() if name in ["top", "bottom"]: shape.size = Vector2(w_px + border_thickness, border_thickness) else: shape.size = Vector2(border_thickness, h_px + border_thickness) var col = CollisionShape2D.new() col.shape = shape wall.position = positions[name] wall.add_child(col) add_child(wall) @onready var label: RichTextLabel = null @onready var uitypebox: ColorRect = null var typing_speed := 0.03 # seconds between characters var typing = false # to prevent overlapping animations func ui_showmesg(t: String) -> void: label = get_node("../UI/bg/RichTextLabel") uitypebox = get_node("../UI/bg") if typing: return # skip if already typing (optional safeguard) uitypebox.visible = true typing = true print(label, " valid? ", is_instance_valid(label)) label.text = t label.visible_characters = 0 await _type_text(t) await wait(4) label = get_node("../UI/bg/RichTextLabel") uitypebox = get_node("../UI/bg") label.visible_characters = 0 uitypebox.visible = false typing = false func _type_text(t: String) -> void: var i := 0 while i < t.length(): i += 1 label.visible_characters = i await wait(typing_speed)