feat: implement the new "Stop N Go" game mode, including phase management, dynamic safe zones, player missions, and dedicated UI with visual effects.
This commit is contained in:
@@ -181,10 +181,8 @@ func clear_highlights():
|
||||
# Check Layer 2 (Overlay Highlight)
|
||||
var l2_pos = Vector3i(cell.x, 2, cell.y)
|
||||
var l2_item = enhanced_gridmap.get_cell_item(l2_pos)
|
||||
# Only clear if it looks like a highlight (e.g. ID 1)
|
||||
# or generally just clear layer 2 if we assume we own it for highlights?
|
||||
# Safest is to check against hover_id or typical highlight IDs.
|
||||
if l2_item != -1:
|
||||
# Only clear if it is a highlight and NOT a Safe Zone (ID 2)
|
||||
if l2_item != -1 and l2_item != 2:
|
||||
enhanced_gridmap.set_cell_item(l2_pos, -1)
|
||||
|
||||
highlighted_cells.clear()
|
||||
|
||||
@@ -99,18 +99,18 @@ func _process(delta):
|
||||
|
||||
if multiplayer.is_server():
|
||||
if current_phase == Phase.GO:
|
||||
var int_timer = int(ceil(phase_timer))
|
||||
if int_timer == 3 and spawned_safe_zones == 0 and phase_timer <= 3.0:
|
||||
_spawn_dynamic_safe_zone()
|
||||
elif int_timer == 2 and spawned_safe_zones == 1 and phase_timer <= 2.0:
|
||||
_spawn_dynamic_safe_zone()
|
||||
elif int_timer == 1 and spawned_safe_zones == 2 and phase_timer <= 1.0:
|
||||
_spawn_dynamic_safe_zone()
|
||||
# Spawn all 3 safe zones at once, 3 seconds before STOP
|
||||
if phase_timer <= 3.0 and spawned_safe_zones == 0:
|
||||
print("[StopNGo] GO phase ending soon. Spawning 3 safe zones...")
|
||||
for i in range(3):
|
||||
_spawn_dynamic_safe_zone()
|
||||
|
||||
if phase_timer <= 0:
|
||||
if current_phase == Phase.GO:
|
||||
print("[StopNGo] GO Timer reached 0. Starting STOP Phase.")
|
||||
_start_phase(Phase.STOP)
|
||||
else:
|
||||
print("[StopNGo] STOP Timer reached 0. Starting GO Phase.")
|
||||
_start_phase(Phase.GO)
|
||||
|
||||
# Update HUD locally
|
||||
@@ -499,8 +499,9 @@ func _is_in_safe_zone(pos: Vector2i) -> bool:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return false
|
||||
|
||||
var floor_tile = gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y))
|
||||
return floor_tile == TILE_SAFE
|
||||
# Check Layer 2 (Overlay layer) for Safe Zone tile
|
||||
var overlay_tile = gridmap.get_cell_item(Vector3i(pos.x, 2, pos.y))
|
||||
return overlay_tile == TILE_SAFE
|
||||
|
||||
func _spawn_dynamic_safe_zone():
|
||||
if not multiplayer.is_server(): return
|
||||
@@ -523,15 +524,17 @@ func _spawn_dynamic_safe_zone():
|
||||
var rect = possible_rects.pick_random()
|
||||
active_safe_zone_rects.append(rect)
|
||||
spawned_safe_zones += 1
|
||||
print("[StopNGo] Spawning Safe Zone %d at %s" % [spawned_safe_zones, rect])
|
||||
|
||||
# Paint floor to TILE_SAFE
|
||||
# Paint Floor 2 (Overlay layer) to TILE_SAFE
|
||||
# This allows seeing items below on Floor 1
|
||||
for rx in range(rect.size.x):
|
||||
for rz in range(rect.size.y):
|
||||
var px = rect.position.x + rx
|
||||
var pz = rect.position.y + rz
|
||||
gridmap.set_cell_item(Vector3i(px, 0, pz), TILE_SAFE)
|
||||
gridmap.set_cell_item(Vector3i(px, 2, pz), TILE_SAFE)
|
||||
if can_rpc() and main:
|
||||
main.rpc("sync_grid_item", px, 0, pz, TILE_SAFE)
|
||||
main.rpc("sync_grid_item", px, 2, pz, TILE_SAFE)
|
||||
|
||||
func _is_valid_safe_zone_area(gridmap: Node, start_x: int, start_z: int, width: int, height: int) -> bool:
|
||||
# Avoid bounds or start/finish cols
|
||||
@@ -546,16 +549,12 @@ func _is_valid_safe_zone_area(gridmap: Node, start_x: int, start_z: int, width:
|
||||
for x in range(start_x, start_x + width):
|
||||
for z in range(start_z, start_z + height):
|
||||
var floor_0 = gridmap.get_cell_item(Vector3i(x, 0, z))
|
||||
var floor_1 = gridmap.get_cell_item(Vector3i(x, 1, z))
|
||||
|
||||
# Floor must be purely TILE_WALKABLE (0)
|
||||
# We no longer check Floor 1 (items) so safe zones can spawn ON TOP of tiles
|
||||
if floor_0 != TILE_WALKABLE:
|
||||
return false
|
||||
|
||||
# Floor 1 must be empty (-1) - no items or obstacles
|
||||
if floor_1 != -1:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func _clear_dynamic_safe_zones():
|
||||
@@ -564,17 +563,19 @@ func _clear_dynamic_safe_zones():
|
||||
if not gridmap: return
|
||||
var main = get_node_or_null("/root/Main")
|
||||
|
||||
print("[StopNGo] Clearing %d active safe zones." % active_safe_zone_rects.size())
|
||||
|
||||
for rect in active_safe_zone_rects:
|
||||
for rx in range(rect.size.x):
|
||||
for rz in range(rect.size.y):
|
||||
var px = rect.position.x + rx
|
||||
var pz = rect.position.y + rz
|
||||
|
||||
# Only clear if it is actually still a safe zone
|
||||
if gridmap.get_cell_item(Vector3i(px, 0, pz)) == TILE_SAFE:
|
||||
gridmap.set_cell_item(Vector3i(px, 0, pz), TILE_WALKABLE)
|
||||
# Only clear layer 2
|
||||
if gridmap.get_cell_item(Vector3i(px, 2, pz)) == TILE_SAFE:
|
||||
gridmap.set_cell_item(Vector3i(px, 2, pz), -1)
|
||||
if can_rpc() and main:
|
||||
main.rpc("sync_grid_item", px, 0, pz, TILE_WALKABLE)
|
||||
main.rpc("sync_grid_item", px, 2, pz, -1)
|
||||
|
||||
active_safe_zone_rects.clear()
|
||||
spawned_safe_zones = 0
|
||||
|
||||
@@ -497,7 +497,7 @@ func _apply_settings():
|
||||
"""Apply current settings to UI elements."""
|
||||
# Apply joystick visibility
|
||||
if virtual_joystick:
|
||||
virtual_joystick.visible = joystick_enabled
|
||||
virtual_joystick.visible = joystick_enabled and _is_touch_device()
|
||||
|
||||
# Apply touch buttons visibility - FORCED ON per request to "just show them"
|
||||
# Apply touch buttons visibility
|
||||
|
||||
Reference in New Issue
Block a user