feat: Introduce an EnhancedGridMap with advanced generation, randomization, pathfinding, and data serialization, along with new player, powerup, and portal managers.

This commit is contained in:
Yogi Wiguna
2026-03-04 17:40:10 +08:00
parent 8f03cc15c5
commit cd7881bc3f
12 changed files with 128 additions and 107 deletions
+16 -13
View File
@@ -1581,12 +1581,15 @@ func request_randomize_item(grid_position: Vector2i):
func sync_grid_item(x: int, y: int, z: int, item: int):
var enhanced_gridmap = $EnhancedGridMap
if enhanced_gridmap:
# WALL-SAFETY CHECK: Block tiles (7-20) from being placed on walls (4) or void (-1)
# PROTECTED FLOOR CHECK: Block tiles (7-20) from being placed on walls (4) or void (-1)
# Note: We allow spawning on Safe Zones, Start, and Finish as it's on Layer 1.
if y == 1 and item >= 7 and item <= 20:
var f0 = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z))
if f0 == 4 or f0 == -1:
# Log and block illegal placement
print("[Main] Blocked illegal tile (%d) placement on wall/void at (%d, %d)" % [item, x, z])
var f1 = enhanced_gridmap.get_cell_item(Vector3i(x, 1, z))
# Block if Layer 0 is Wall (4) or Void (-1)
# OR Layer 1 is already a wall (4 or 13)
if f0 in [4, -1] or f1 == 4 or f1 == 13:
return
enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item)
@@ -1607,10 +1610,11 @@ func sync_grid_items_batch(data: Array):
var z = entry.get("z", 0)
var item = entry.get("item", -1)
# WALL-SAFETY CHECK
# PROTECTED FLOOR CHECK
if y == 1 and item >= 7 and item <= 20:
var f0 = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z))
if f0 == 4 or f0 == -1:
var f1 = enhanced_gridmap.get_cell_item(Vector3i(x, 1, z))
if f0 in [4, -1] or f1 == 4 or f1 == 13:
continue
enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item)
@@ -1625,13 +1629,12 @@ func randomize_game_grid():
var enhanced_gridmap = $EnhancedGridMap
if enhanced_gridmap:
# Randomize Floor 1 using ScarcityController
enhanced_gridmap.randomize_floor(1, ScarcityController.get_random_tile_id)
# Sync to clients if needed (usually handled by initial state sync or explicit item syncs)
# Since Main.gd doesn't have a "Sync Floor" RPC, we rely on clients running the same seed or syncing individual cells.
# For now, let's assume server authority + sync on connect handles it, or add sync loop if critical.
pass
# Use density-aware callable: 60% chance for a real tile, 40% for none
var density_callable = func():
if randf() > 0.6: return -1
return ScarcityController.get_random_tile_id()
enhanced_gridmap.randomize_floor(1, density_callable)
@rpc("authority", "call_local", "reliable")
func sync_full_grid_data_stop_n_go(floor0: PackedInt32Array, floor1: PackedInt32Array, cols: int, rows: int):
+2 -11
View File
@@ -32,7 +32,6 @@
[ext_resource type="Texture2D" uid="uid://3up2su2e0lfa" path="res://assets/graphics/touch_control/freeze_area.png" id="28_fv21b"]
[ext_resource type="Texture2D" uid="uid://ckhdyxnho6sjp" path="res://assets/graphics/touch_control/spawn_tile.png" id="28_j8jky"]
[ext_resource type="Texture2D" uid="uid://b2vhatfmufn3d" path="res://assets/graphics/touch_control/ghost.png" id="33_5q0nq"]
[ext_resource type="Texture2D" uid="uid://cdwk17moidkj2" path="res://assets/graphics/touch_control/knock_tekton.png" id="35_fuf3a"]
[ext_resource type="Texture2D" uid="uid://biun2yvglxgij" path="res://assets/graphics/touch_control/grab_tekton.png" id="36_pibwh"]
[ext_resource type="Script" uid="uid://86ikh0wuqk7v" path="res://scripts/ui/powerup_inventory_ui.gd" id="powerup_ui_script"]
[ext_resource type="Script" uid="uid://b54tfa0n6kogi" path="res://scripts/managers/touch_controls.gd" id="touch_manager"]
@@ -99,6 +98,7 @@ columns = 14
rows = 14
floors = 2
auto_randomize = true
immutable_items = Array[int]([4])
metadata/_editor_floor_ = Vector3(0, 1, 0)
[node name="Camera3D" type="Camera3D" parent="." unique_id=1200003163]
@@ -9808,16 +9808,7 @@ flat = true
icon_alignment = 1
expand_icon = true
[node name="TektonKnockBtn" type="Button" parent="TouchControls/TouchControls/ActionsBtn" unique_id=2133168886]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
icon = ExtResource("35_fuf3a")
flat = true
icon_alignment = 1
expand_icon = true
[node name="TektonThrowBtn" type="Button" parent="TouchControls/TouchControls/ActionsBtn" unique_id=2097928368]
[node name="TektonGrabBtn" type="Button" parent="TouchControls/TouchControls/ActionsBtn" unique_id=2097928368]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
+31
View File
@@ -707,6 +707,9 @@ var immunity_timer: float = 0.0
@rpc("any_peer", "call_local")
func apply_stagger(duration: float = 1.5):
if is_carrying_tekton:
return # Cannot be staggered while carrying a Tekton
if immunity_timer > 0:
return # Immune!
@@ -2191,6 +2194,34 @@ func sync_throw_tekton(target_pos: Vector2i):
print("[Player %s] Threw Tekton to %s (Dist: %s)" % [name, target_pos, target_pos.distance_to(tekton.current_position)])
func drop_tekton():
"""Drops the Tekton at the current player position immediately."""
if not is_multiplayer_authority() or not is_carrying_tekton:
return
if is_multiplayer_authority() and can_rpc():
rpc("sync_drop_tekton")
@rpc("any_peer", "call_local", "reliable")
func sync_drop_tekton():
if carried_tekton:
var tekton = carried_tekton
carried_tekton = null
is_carrying_tekton = false
# Set its position to player's current position (but on ground)
var drop_pos = grid_to_world(current_position)
tekton.global_position = drop_pos
if tekton.has_method("set_carried"):
tekton.set_carried(false)
# Trigger landing effects (minimal scale)
if tekton.has_method("on_thrown_landing"):
tekton.on_thrown_landing(self, 1.0) # Minimal scale impact
print("[Player %s] Dropped Tekton at %s" % [name, current_position])
# is_attack_mode is already declared at top of file (or inherited?)
# Keeping is_knock_mode here for now or moving it up would be better, but let's just fix the error first.
var is_knock_mode: bool = false # Yellow mode for knocking Tekton