feat: Add Tekton character model, implement in-game message bar, global match timer UI, and camera context manager.

This commit is contained in:
Yogi Wiguna
2026-02-12 14:56:57 +08:00
parent 5275c4acd8
commit a05e3123b4
15 changed files with 324 additions and 30 deletions
+32 -18
View File
@@ -150,12 +150,16 @@ var is_recovering: bool = false # True when shrunk/waiting
@rpc("any_peer", "call_local", "reliable")
func on_thrown_landing(attacker: Node = null, intensity: float = 1.0):
"""Called when Tekton lands after being thrown or knocked."""
# Prevent double-triggering (re-entrancy)
if is_recovering:
return
is_recovering = true
print("[Tekton] Landed/Knocked! Shrinking and waiting... (Intensity: %.1f)" % intensity)
_flash_damage() # Add visual flash too? Why not.
is_recovering = true
# Disable movement/interaction logic temporarily
var controller = get_node_or_null("TektonController")
if controller and controller.get("timer"):
@@ -176,6 +180,13 @@ func on_thrown_landing(attacker: Node = null, intensity: float = 1.0):
var t = create_tween()
t.tween_property(mesh, "scale", base_scale * 0.5, 0.2).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
# Spawn tiles (as requested "tekton will spawn a tiles around that floor also")
if is_multiplayer_authority():
spawn_tiles_around(int(8 * intensity))
# Floor Freeze (Visual/Instant - Run on all clients locally)
temporarily_change_floor(current_position, 1, 6, 3.0)
# Wait 3 seconds
await get_tree().create_timer(3.0).timeout
@@ -193,18 +204,8 @@ func on_thrown_landing(attacker: Node = null, intensity: float = 1.0):
if controller and controller.has_method("_start_timer"):
if is_multiplayer_authority() and not is_carried:
controller._start_timer()
# Spawn tiles (as requested "tekton will spawn a tiles around that floor also")
if is_multiplayer_authority():
spawn_tiles_around(int(8 * intensity))
# Floor Freeze (Visual/Instant - Run on all clients locally)
temporarily_change_floor(current_position, 1, 6, 3.0)
# Stun nearby players handled by Thrower (Player.gd) or here?
# Player.gd handles the stun call because it knows the impact zone context better?
# Actually, Player.gd calls this function. Player.gd *also* iterates players to stun them.
# That is fine.
func temporarily_change_floor(center: Vector2i, radius: int, new_id: int, duration: float):
if not enhanced_gridmap: return
@@ -221,13 +222,21 @@ func temporarily_change_floor(center: Vector2i, radius: int, new_id: int, durati
# Only change if not already the new ID (avoid redundant updates or overriding existing freeze)
if original != new_id:
# PRE-FIX: If we capture a "Hole" (Void or Pickup 7-14) here, we must record it as Floor (0)
# so that we restore a valid floor later.
if original == -1 or (original >= 7 and original <= 14):
print("[Tekton] Warning: Captured floor at %s was ID %d (Invalid/Pickup). Recording as FLOOR (0)." % [pos, original])
original = 0
changed_cells[pos] = original
# Set locally immediately
enhanced_gridmap.set_cell_item(cell_3d, new_id)
print("[Tekton] Applying Floor ID %d at %s (Replacing ID %d)" % [new_id, pos, original])
await get_tree().create_timer(duration).timeout
# Restore locally
var restored_count = 0
for pos in changed_cells:
var original = changed_cells[pos]
var current_cell = Vector3i(pos.x, 0, pos.y)
@@ -235,12 +244,17 @@ func temporarily_change_floor(center: Vector2i, radius: int, new_id: int, durati
# Only restore if it hasn't been changed to something else in meantime
if current == new_id:
# Fallback: Fix "Hole" bugs where original was Void (-1) or a Pickup (7-14)
# Pickups (7-14) on Floor Layer (0) cause holes because they lack floor geometry.
# If we find a pickup here, we MUST restore to Floor (0) instead of the Pickup.
if original == -1 or (original >= 7 and original <= 14):
print("[Tekton] Warning: Restoring floor at %s was ID %d (Invalid/Pickup). Forcing to FLOOR (0)." % [pos, original])
original = 0
enhanced_gridmap.set_cell_item(current_cell, original)
# Stun nearby players handled by Thrower (Player.gd) or here?
# Player.gd handles the stun call because it knows the impact zone context better?
# Actually, Player.gd calls this function. Player.gd *also* iterates players to stun them.
# That is fine.
restored_count += 1
print("[Tekton] Restored %d/%d frozen floors at %s" % [restored_count, changed_cells.size(), center])
func spawn_tiles_around(count: int = 4):
"""Spawns a mix of normal and special tiles in a radius."""