experimental: remove Tekton Doors entirely

- Delete portal_mode_manager.gd, portal_door.gd, portal_door.tscn
- Strip all Tekton Doors logic from main.gd, player.gd, lobby.gd,
  lobby_room.gd, lobby_manager.gd, camera_context_manager.gd,
  music_manager.gd, tekton.gd, enhanced_gridmap.gd,
  playerboard_manager.gd, special_tiles_manager.gd
- Remove TK enum (TEKTON_DOORS=2), mode_config schema, arena area
- Update tests: 3 modes instead of 4
- Strip HowToPlay tab from main.tscn
This commit is contained in:
god
2026-07-06 00:18:59 +08:00
parent 0ab00afd37
commit 114748a54f
31 changed files with 4493 additions and 1535 deletions
+1 -6
View File
@@ -86,12 +86,7 @@ var sng_go_option: OptionButton
var sng_stop_option: OptionButton
var sng_goals_option: OptionButton
var doors_settings_container: HBoxContainer
var doors_swap_option: OptionButton
var doors_refresh_option: OptionButton
var doors_goals_option: OptionButton
# UI References - Player Slots
# Gauntlet settings
@onready var players_container = $LobbyPanel/PlayersContainer
@onready var players_container2 = $LobbyPanel/PlayersContainer2
@onready var player_slots: Array[Control] = []
+5 -179
View File
@@ -12,10 +12,8 @@ var touch_controls
var camera_context_manager
var stop_n_go_manager
var stop_n_go_winner_id: int = -1 # Track who finished first in Stop n Go mode
var portal_mode_winner_id: int = -1
var is_match_ended: bool = false
var obstacle_manager
var portal_mode_manager
var gauntlet_manager
var vfx_manager
@@ -146,8 +144,6 @@ func _apply_arena_background():
texture_path = "res://assets/graphics/level_bg/placeholder_classic.jpg" # Fallback texture
_instantiate_3d_arena("res://scenes/arena/freemode.tscn")
_hide_ground_tiles()
"Tekton Doors Arena":
texture_path = "res://assets/graphics/level_bg/placeholder_tekton_doors.jpg"
"Gauntlet Arena":
texture_path = "res://assets/graphics/level_bg/placeholder_classic.jpg"
_instantiate_3d_arena("res://scenes/arena/gauntlet.tscn")
@@ -207,14 +203,6 @@ func _setup_effect_elevation():
em.mesh_library = ml
print("[Main] MeshLibrary elevation applied: Wall(4) and Freeze(5) at Y=0.8")
@rpc("any_peer", "call_local", "reliable")
func sync_portal_configs(configs: Array):
if portal_mode_manager:
# Temporarily store the configs and trigger spawn
# Note: We use a custom property in manager to pass this
portal_mode_manager.set_meta("door_configs", configs)
portal_mode_manager._spawn_portal_doors()
# Force gridmap cell size to match player logic (1, 0.05, 1) - >0.001 to avoid errors
var em = $EnhancedGridMap
if em:
@@ -245,12 +233,6 @@ func _init_managers():
add_child(stop_n_go_manager)
# No direct initialize() yet, but we'll call start_game_mode later
# Portal manager for Tekton Doors mode
if LobbyManager.game_mode == "Tekton Doors":
portal_mode_manager = load("res://scripts/managers/portal_mode_manager.gd").new()
portal_mode_manager.name = "PortalModeManager"
add_child(portal_mode_manager)
portal_mode_manager.initialize(self , $EnhancedGridMap)
# Gauntlet manager for Candy Pump Survival mode
if LobbyManager.game_mode == "Candy Pump Survival":
@@ -619,8 +601,6 @@ func _setup_host_game():
# Spawning and arena setup
if LobbyManager.game_mode == "Stop n Go" and stop_n_go_manager:
stop_n_go_manager._setup_arena()
elif LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
portal_mode_manager.setup_arena_locally()
elif LobbyManager.game_mode == "Candy Pump Survival" and gauntlet_manager:
gauntlet_manager._setup_arena()
else:
@@ -725,10 +705,6 @@ func _setup_client_game():
add_player_character(i, true)
print("Client: Pre-spawned potential bot ", i)
# Initialize arena locally for Tekton Doors
if LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
portal_mode_manager.setup_arena_locally()
# Initialize arena locally for Candy Pump Survival
if LobbyManager.game_mode == "Candy Pump Survival" and gauntlet_manager:
gauntlet_manager._apply_arena_setup()
@@ -833,14 +809,10 @@ func _start_game():
gauntlet_manager.setup_mission_tiles()
# Spawn Static Tektons and random tiles BEFORE countdown (Free Mode Only)
# Exclude for Stop n Go and Tekton Doors
if LobbyManager.game_mode != "Stop n Go" and LobbyManager.game_mode != "Tekton Doors" and LobbyManager.game_mode != "Candy Pump Survival":
# Exclude for Stop n Go and Candy Pump Survival
if LobbyManager.game_mode != "Stop n Go" and LobbyManager.game_mode != "Candy Pump Survival":
spawn_static_tektons()
# Tekton Doors: Randomize connections BEFORE countdown so colors show
if LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
portal_mode_manager._randomize_connections()
# STOP N GO: Rotate players to face East BEFORE countdown
if LobbyManager.game_mode == "Stop n Go" and stop_n_go_manager:
stop_n_go_manager.rotate_players_to_start()
@@ -866,13 +838,6 @@ func _start_game():
if goals_cycle_manager:
var match_duration = LobbyManager.get_match_duration()
goals_cycle_manager.start_match(float(match_duration), false) # No cycles for Stop n Go
elif LobbyManager.game_mode == "Tekton Doors":
if portal_mode_manager:
portal_mode_manager.start_game_mode()
if goals_cycle_manager:
var match_duration = LobbyManager.get_match_duration()
goals_cycle_manager.start_match(float(match_duration))
elif LobbyManager.game_mode == "Candy Pump Survival":
if gauntlet_manager:
gauntlet_manager.start_game_mode()
@@ -986,12 +951,6 @@ func _assign_random_spawn_positions():
_assign_stop_n_go_spawn_positions(all_players)
return
# Tekton Doors Custom Spawn Logic
if LobbyManager.game_mode == "Tekton Doors":
var all_players = get_tree().get_nodes_in_group("Players")
_assign_portal_mode_spawn_positions(all_players)
return
# If static positions were not calculated yet, do it now to avoid players spawning in them
if reserved_static_positions.is_empty() and LobbyManager.game_mode != "Stop n Go":
if not static_tekton_manager:
@@ -1116,77 +1075,6 @@ func _assign_stop_n_go_spawn_positions(all_players: Array):
print("[StopNGo] Assigned spawn %s to player %s" % [assigned_pos, player.name])
func _assign_portal_mode_spawn_positions(all_players: Array):
"""Assigns spawns to different quadrants for Tekton Doors mode, avoiding stands and intersections."""
if not portal_mode_manager:
_assign_random_spawn_positions() # Fallback
return
# Sort players for deterministic assignment
all_players.sort_custom(func(a, b): return a.name.to_int() < b.name.to_int())
# Get baseline quadrant centers (3,3), (10,3), etc.
var base_spawn_points = portal_mode_manager.get_spawn_points()
var spawn_index = 0
var assigned_positions: Array[Vector2i] = []
for player in all_players:
var center_pos = base_spawn_points[spawn_index % base_spawn_points.size()]
var assigned_pos = center_pos # Fallback position
# Spiral search for a valid spot (walkable, not in stand zone, not occupied)
var found = false
for radius in range(0, 5): # Increase search radius
for dx in range(-radius, radius + 1):
for dz in range(-radius, radius + 1):
# Only check the "ring" at the current radius
if abs(dx) != radius and abs(dz) != radius and radius > 0:
continue
var test_pos = center_pos + Vector2i(dx, dz)
# 1. Check map bounds
var em = $EnhancedGridMap
if not em or test_pos.x < 0 or test_pos.x >= em.columns or test_pos.y < 0 or test_pos.y >= em.rows:
continue
# 2. Check if walkable floor (Floor 0, ID 0)
if em.get_cell_item(Vector3i(test_pos.x, 0, test_pos.y)) != 0:
continue
# 3. Check if reserved for a Static Tekton Stand (3x3 area, use 2-tile buffer)
var is_reserved = false
for reserved in reserved_static_positions:
if abs(test_pos.x - reserved.x) <= 2 and abs(test_pos.y - reserved.y) <= 2:
is_reserved = true
break
if is_reserved:
continue
# 4. Check if occupied by another already-assigned player
if assigned_positions.has(test_pos):
continue
assigned_pos = test_pos
found = true
break
if found: break
if found: break
assigned_positions.append(assigned_pos)
# Sync and place
player.position = player.grid_to_world(assigned_pos)
player.current_position = assigned_pos
player.is_player_moving = false
player.spawn_point_selected = true
if can_rpc():
player.rpc("set_spawn_position", assigned_pos)
spawn_index += 1
print("[PortalMode] Assigned Quadrant Pos %s to player %s" % [assigned_pos, player.name])
# =============================================================================
# Tekton NPC Management
# =============================================================================
@@ -1639,9 +1527,6 @@ func sync_game_start(player_list: Array, is_turn_based: bool):
stop_n_go_manager.name = "StopNGoManager"
add_child(stop_n_go_manager)
stop_n_go_manager.activate_client_side()
elif LobbyManager.game_mode == "Tekton Doors":
if portal_mode_manager:
portal_mode_manager.activate_client_side()
# Initialize leaderboard for all peers (after a delay to ensure players loaded)
call_deferred("_deferred_init_leaderboard")
@@ -1878,7 +1763,7 @@ func randomize_item_at_position(grid_position: Vector2i):
if is_ground:
var get_mode_specific_tile = func():
if LobbyManager.game_mode != "Stop n Go" and LobbyManager.game_mode != "Tekton Doors" and LobbyManager.game_mode != "Candy Pump Survival":
if LobbyManager.game_mode != "Stop n Go" and LobbyManager.game_mode != "Candy Pump Survival":
# 60% Chance for Common (7-10), 40% for PowerUp
if randf() <= 0.6:
return [7, 8, 9, 10].pick_random()
@@ -1923,14 +1808,7 @@ func sync_grid_item(x: int, y: int, z: int, item: int):
# OR Layer 1 is already a wall (4)
if f0 in [4, -1] or f1 == 4:
return
# TEKTON DOORS: Prevent placing items on portal doors
if LobbyManager.is_game_mode(GameMode.Mode.TEKTON_DOORS):
var doors = get_tree().get_nodes_in_group("PortalDoors")
for door in doors:
var door_grid = enhanced_gridmap.local_to_map(enhanced_gridmap.to_local(door.global_position))
if door_grid.x == x and door_grid.z == z:
return
enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item)
# Force visual update
@@ -2098,17 +1976,6 @@ func sync_grid_items_batch(data: Array):
if f0 in [4, -1] or f1 == 4:
continue
# TEKTON DOORS: Prevent placing items on portal doors
if LobbyManager.is_game_mode(GameMode.Mode.TEKTON_DOORS) and y == 1:
var doors = get_tree().get_nodes_in_group("PortalDoors")
var on_door = false
for door in doors:
var door_grid = enhanced_gridmap.local_to_map(enhanced_gridmap.to_local(door.global_position))
if door_grid.x == x and door_grid.z == z:
on_door = true
break
if on_door: continue
enhanced_gridmap.set_cell_item(Vector3i(x, y, z), item)
# Force visual update ONCE after batch
@@ -2116,7 +1983,7 @@ func sync_grid_items_batch(data: Array):
enhanced_gridmap.update_grid_data()
func randomize_game_grid():
if LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors":
if LobbyManager.game_mode == "Stop n Go":
return # These modes manage their own arena setup and item spawning
var enhanced_gridmap = $EnhancedGridMap
@@ -2177,10 +2044,6 @@ func request_full_grid_sync():
if sender_id in multiplayer.get_peers():
rpc_id(sender_id, "sync_full_grid_data", grid_data)
print("[Main] Server: Sent grid sync rpc_id to %d" % sender_id)
# If Tekton Doors, sync portal connections too
if LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
portal_mode_manager.sync_to_client(sender_id)
@rpc("authority", "call_local", "reliable")
func sync_full_grid_data(data: PackedInt32Array):
@@ -2197,13 +2060,6 @@ func sync_full_grid_data(data: PackedInt32Array):
stop_n_go_manager.name = "StopNGoManager"
add_child(stop_n_go_manager)
stop_n_go_manager._apply_arena_setup()
elif LobbyManager.game_mode == "Tekton Doors":
if not portal_mode_manager:
portal_mode_manager = load("res://scripts/managers/portal_mode_manager.gd").new()
portal_mode_manager.name = "PortalModeManager"
add_child(portal_mode_manager)
portal_mode_manager.initialize(self , enhanced_gridmap)
portal_mode_manager.setup_arena_locally()
else:
# Freemode: Ensure Floor 0 is entirely walkable (reset stale state from previous modes)
for x in range(enhanced_gridmap.columns):
@@ -2337,27 +2193,6 @@ func sync_game_end_stop_n_go(winner_id: int):
# Trigger match end
_on_match_ended()
@rpc("any_peer", "call_local", "reliable")
func sync_game_end_portal_mode(winner_id: int):
print("[TEKTON DOORS] Game ended! Winner: ", winner_id)
portal_mode_winner_id = winner_id
var winner_name = "Player " + str(winner_id)
var player_node = get_node_or_null(str(winner_id))
if player_node:
winner_name = player_node.display_name
# Broadcast win
add_message_to_bar("MATCH COMPLETE", winner_name + " Wins with 8 Missions!", MessageType.GOAL)
# Stop logic
if portal_mode_manager:
if portal_mode_manager.swap_timer: portal_mode_manager.swap_timer.stop()
if portal_mode_manager.tile_refresh_timer: portal_mode_manager.tile_refresh_timer.stop()
# Trigger match end
_on_match_ended()
func _on_match_ended():
"""Called when the global match timer ends - show game over screen."""
if is_match_ended:
@@ -2422,9 +2257,6 @@ func _show_game_over_panel():
if stop_n_go_manager and stop_n_go_manager.hud_layer:
stop_n_go_manager.hud_layer.hide()
if portal_mode_manager and portal_mode_manager.hud_layer:
portal_mode_manager.hud_layer.hide()
# =========================================================================
# Gather + sort player data
# =========================================================================
@@ -2446,12 +2278,6 @@ func _show_game_over_panel():
if b.peer_id == stop_n_go_winner_id: return false
return a.score > b.score
)
elif LobbyManager.game_mode == "Tekton Doors" and portal_mode_winner_id != -1:
all_player_scores.sort_custom(func(a, b):
if a.peer_id == portal_mode_winner_id: return true
if b.peer_id == portal_mode_winner_id: return false
return a.score > b.score
)
else:
all_player_scores.sort_custom(func(a, b): return a.score > b.score)
-19
View File
@@ -2249,25 +2249,6 @@ text = "[b]Stop n Go[/b]
- Your objective is to reach the mission tiles at the far end of the arena and safely carry them back to your starting zone.
- The first player to complete 8 missions and reach the finish floor wins."
[node name="Tekton Doors" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456799]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
metadata/_tab_index = 2
[node name="RichTextLabel" type="RichTextLabel" parent="HowToPlayPanel/Panel/VBox/TabContainer/Tekton Doors" unique_id=123456800]
layout_mode = 2
bbcode_enabled = true
text = "[b]Tekton Doors[/b]
- Navigate a sprawling arena connected by color-coded portal doors.
- Grab tiles and match goal patterns to earn mission completions.
- Use doors to quickly teleport across rooms, but watch out for closures and traps.
- The first player to complete 8 missions and reach the finish room wins."
[node name="Controls" type="MarginContainer" parent="HowToPlayPanel/Panel/VBox/TabContainer" unique_id=123456805]
visible = false
layout_mode = 2
+1 -8
View File
@@ -1767,14 +1767,7 @@ func start_movement_along_path(path: Array, clear_visual: bool = true, force: bo
if sng_manager and sng_manager.has_method("check_win_condition"):
if sng_manager.check_win_condition(name.to_int(), current_position):
sng_main.rpc("sync_game_end_stop_n_go", name.to_int())
# Tekton Doors Win Check
elif LobbyManager.game_mode == "Tekton Doors":
var main_node = get_tree().root.get_node_or_null("Main")
if main_node and main_node.portal_mode_manager:
if main_node.portal_mode_manager.check_win_condition(name.to_int(), current_position):
main_node.rpc("sync_game_end_portal_mode", name.to_int())
# FORCE SNAP: Update target visual position to the perfect grid center
# This ensures that when interpolation resumes (in _process), it pulls to the correct spot
target_visual_position = grid_to_world(current_position)
-92
View File
@@ -1,92 +0,0 @@
[gd_scene load_steps=8 format=3 uid="uid://portal_door_001"]
[ext_resource type="Script" path="res://scripts/portal_door.gd" id="1_script"]
[sub_resource type="BoxMesh" id="BoxMesh_frame"]
size = Vector3(0.15, 2.2, 0.15)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_frame"]
albedo_color = Color(0.1, 0.5, 0.8, 1)
metallic = 0.8
roughness = 0.2
[sub_resource type="PlaneMesh" id="PlaneMesh_ground"]
size = Vector2(1.0, 1.0)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ground"]
transparency = 1
albedo_color = Color(1, 1, 1, 0.4)
emission_enabled = true
emission = Color(1, 1, 1, 1)
emission_energy_multiplier = 1.0
[sub_resource type="PlaneMesh" id="PlaneMesh_vortex"]
size = Vector2(1.4, 2.1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vortex"]
transparency = 1
albedo_color = Color(0.0, 0.6, 1.0, 0.4)
emission_enabled = true
emission = Color(0.0, 0.4, 1.0, 1)
emission_energy_multiplier = 5.0
[sub_resource type="BoxShape3D" id="BoxShape3D_trigger"]
size = Vector3(1.4, 2.1, 0.8)
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_portal"]
properties/0/path = NodePath(":target_room_id")
properties/0/spawn = true
properties/0/replication_mode = 2
properties/1/path = NodePath(":target_door_id")
properties/1/spawn = true
properties/1/replication_mode = 2
properties/2/path = NodePath(":is_active")
properties/2/spawn = true
properties/2/replication_mode = 2
properties/3/path = NodePath(":portal_color")
properties/3/spawn = true
properties/3/replication_mode = 2
[node name="PortalDoor" type="StaticBody3D"]
script = ExtResource("1_script")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1, 0)
shape = SubResource("BoxShape3D_trigger")
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_portal")
[node name="Frame_Left" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.75, 1.1, 0)
mesh = SubResource("BoxMesh_frame")
surface_material_override/0 = SubResource("StandardMaterial3D_frame")
[node name="Frame_Right" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.75, 1.1, 0)
mesh = SubResource("BoxMesh_frame")
surface_material_override/0 = SubResource("StandardMaterial3D_frame")
[node name="Frame_Top" type="MeshInstance3D" parent="."]
transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 2.2, 0)
mesh = SubResource("BoxMesh_frame")
surface_material_override/0 = SubResource("StandardMaterial3D_frame")
[node name="Vortex" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1.1, 0)
mesh = SubResource("PlaneMesh_vortex")
surface_material_override/0 = SubResource("StandardMaterial3D_vortex")
[node name="GroundIndicator" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0.4)
mesh = SubResource("PlaneMesh_ground")
surface_material_override/0 = SubResource("StandardMaterial3D_ground")
[node name="Area3D" type="Area3D" parent="."]
collision_layer = 0
collision_mask = 2
[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1, 0)
shape = SubResource("BoxShape3D_trigger")
+2 -18
View File
@@ -51,9 +51,6 @@ func _init(p_lobby: Control):
LobbyManager.sng_go_duration_changed.connect(_on_sng_update)
LobbyManager.sng_stop_duration_changed.connect(_on_sng_update)
LobbyManager.sng_required_goals_changed.connect(_on_sng_update)
LobbyManager.doors_swap_time_changed.connect(_on_doors_update)
LobbyManager.doors_refresh_time_changed.connect(_on_doors_update)
LobbyManager.doors_required_goals_changed.connect(_on_doors_update)
FriendManager.lobby_invite_received.connect(_on_lobby_invite_received)
@@ -136,21 +133,8 @@ func _on_sng_update(_val: int = 0) -> void:
if go_idx != -1: lobby.sng_go_option.selected = go_idx
var stop_idx = [3, 4, 5].find(LobbyManager.sng_stop_duration)
if stop_idx != -1: lobby.sng_stop_option.selected = stop_idx
var goals_idx = [5, 8, 12].find(LobbyManager.sng_required_goals)
if goals_idx != -1: lobby.sng_goals_option.selected = goals_idx
func _on_doors_update(_val: int = 0) -> void:
if not lobby.doors_swap_option: return
var swap_idx = [10, 15, 30].find(LobbyManager.doors_swap_time)
if swap_idx != -1: lobby.doors_swap_option.selected = swap_idx
var refresh_idx = [15, 25, 40].find(LobbyManager.doors_refresh_time)
if refresh_idx != -1: lobby.doors_refresh_option.selected = refresh_idx
var goals_idx = [5, 8, 12].find(LobbyManager.doors_required_goals)
if goals_idx != -1: lobby.doors_goals_option.selected = goals_idx
# =============================================================================
# LobbyManager Signal Handlers
# =============================================================================
var goals_idx2 = [5, 8, 12].find(LobbyManager.sng_required_goals)
if goals_idx2 != -1: lobby.sng_goals_option.selected = goals_idx2
func _on_room_joined(room_data: Dictionary) -> void:
lobby._show_panel("lobby")