attempt to make stop n go gamemode
This commit is contained in:
@@ -40,6 +40,8 @@ extends Control
|
||||
@onready var enable_timer_label = $LobbyPanel/TopBar/SettingsSection/EnableTimerLabel
|
||||
@onready var scarcity_option = $LobbyPanel/TopBar/SettingsSection/ScarcityOption
|
||||
@onready var scarcity_label = $LobbyPanel/TopBar/SettingsSection/ScarcityLabel
|
||||
@onready var game_mode_option = $LobbyPanel/TopBar/SettingsSection/GameModeOption
|
||||
@onready var game_mode_text_label = $LobbyPanel/TopBar/SettingsSection/GameModeTextLabel
|
||||
|
||||
# UI References - Player Slots
|
||||
@onready var players_container = $LobbyPanel/PlayersContainer
|
||||
@@ -145,6 +147,9 @@ func _ready():
|
||||
if scarcity_option:
|
||||
scarcity_option.item_selected.connect(_on_scarcity_selected)
|
||||
|
||||
if game_mode_option:
|
||||
game_mode_option.item_selected.connect(_on_game_mode_selected)
|
||||
|
||||
# Connect LobbyManager signals
|
||||
LobbyManager.room_list_updated.connect(_on_room_list_updated)
|
||||
LobbyManager.room_joined.connect(_on_room_joined)
|
||||
@@ -160,6 +165,7 @@ func _ready():
|
||||
LobbyManager.character_changed.connect(_on_character_changed)
|
||||
LobbyManager.area_changed.connect(_on_area_changed)
|
||||
LobbyManager.scarcity_mode_changed.connect(_on_scarcity_mode_changed)
|
||||
LobbyManager.game_mode_changed.connect(_on_game_mode_changed)
|
||||
LobbyManager.player_list_changed.connect(_update_player_slots)
|
||||
|
||||
# Connect NakamaManager signals
|
||||
@@ -354,6 +360,20 @@ func _on_scarcity_mode_changed(mode: String) -> void:
|
||||
if scarcity_label:
|
||||
scarcity_label.text = mode
|
||||
|
||||
func _on_game_mode_selected(index: int) -> void:
|
||||
if not LobbyManager.is_host: return
|
||||
var mode = game_mode_option.get_item_text(index)
|
||||
LobbyManager.set_game_mode(mode)
|
||||
|
||||
func _on_game_mode_changed(mode: String) -> void:
|
||||
if game_mode_option:
|
||||
for i in range(game_mode_option.item_count):
|
||||
if game_mode_option.get_item_text(i) == mode:
|
||||
game_mode_option.selected = i
|
||||
break
|
||||
if game_mode_text_label:
|
||||
game_mode_text_label.text = mode
|
||||
|
||||
|
||||
func _update_random_spawn_label(enabled: bool) -> void:
|
||||
if random_spawn_label:
|
||||
@@ -430,6 +450,11 @@ func _on_room_joined(room_data: Dictionary) -> void:
|
||||
area_right_btn.disabled = not is_host
|
||||
area_name_label.text = LobbyManager.get_selected_area()
|
||||
|
||||
# Game Mode Update
|
||||
if game_mode_option: game_mode_option.visible = is_host
|
||||
if game_mode_text_label: game_mode_text_label.visible = not is_host
|
||||
_on_game_mode_changed(LobbyManager.game_mode)
|
||||
|
||||
_update_player_slots()
|
||||
connection_status.text = "Connected to room"
|
||||
|
||||
|
||||
@@ -411,6 +411,29 @@ theme_override_colors/font_color = Color(0.647, 0.996, 0.224, 1)
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "Normal"
|
||||
|
||||
[node name="GameModeSpacer" type="Control" parent="LobbyPanel/TopBar/SettingsSection" unique_id=1261898888]
|
||||
custom_minimum_size = Vector2(15, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GameModeOption" type="OptionButton" parent="LobbyPanel/TopBar/SettingsSection" unique_id=448678888]
|
||||
custom_minimum_size = Vector2(105, 28)
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("5_pc087")
|
||||
theme_override_font_sizes/font_size = 11
|
||||
selected = 0
|
||||
item_count = 2
|
||||
popup/item_0/text = "Freemode"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "Stop n Go"
|
||||
popup/item_1/id = 1
|
||||
|
||||
[node name="GameModeTextLabel" type="Label" parent="LobbyPanel/TopBar/SettingsSection" unique_id=191738888]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.647, 0.996, 0.224, 1)
|
||||
theme_override_font_sizes/font_size = 11
|
||||
text = "Freemode"
|
||||
|
||||
[node name="HostBanner" type="PanelContainer" parent="LobbyPanel" unique_id=1670701936]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
|
||||
+58
-11
@@ -10,6 +10,7 @@ var goals_cycle_manager
|
||||
var screen_shake_manager
|
||||
var touch_controls
|
||||
var camera_context_manager
|
||||
var stop_n_go_manager
|
||||
|
||||
# Minimal local state
|
||||
var _connection_check_timer: float = 0.0
|
||||
@@ -87,6 +88,13 @@ func _init_managers():
|
||||
add_child(goals_cycle_manager)
|
||||
goals_cycle_manager.initialize(self)
|
||||
|
||||
# Stop n Go manager for phase-based gameplay
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
stop_n_go_manager = load("res://scripts/managers/stop_n_go_manager.gd").new()
|
||||
stop_n_go_manager.name = "StopNGoManager"
|
||||
add_child(stop_n_go_manager)
|
||||
# No direct initialize() yet, but we'll call start_game_mode later
|
||||
|
||||
# Screen shake manager for impact feedback
|
||||
screen_shake_manager = load("res://scripts/managers/screen_shake.gd").new()
|
||||
screen_shake_manager.name = "ScreenShakeManager"
|
||||
@@ -516,7 +524,10 @@ func _start_game():
|
||||
rpc("set_current_turn", next_player)
|
||||
|
||||
# Start the global match timer (this also starts the first cycle)
|
||||
if goals_cycle_manager:
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
if stop_n_go_manager:
|
||||
stop_n_go_manager.start_game_mode()
|
||||
elif goals_cycle_manager:
|
||||
var match_duration = LobbyManager.get_match_duration()
|
||||
goals_cycle_manager.start_match(float(match_duration))
|
||||
|
||||
@@ -711,7 +722,6 @@ func _create_tekton(pos: Vector2i, tekton_id: int, is_static: bool = false):
|
||||
# If Static, swap controller
|
||||
if is_static:
|
||||
# tekton.is_static_turret = true # Already set above
|
||||
|
||||
var old_controller = tekton.get_node_or_null("TektonController")
|
||||
if old_controller:
|
||||
old_controller.queue_free()
|
||||
@@ -724,7 +734,6 @@ func _create_tekton(pos: Vector2i, tekton_id: int, is_static: bool = false):
|
||||
print("[Main] Spawned Tekton at %s (ID: %d)" % [pos, tekton_id])
|
||||
|
||||
|
||||
|
||||
func _precalculate_static_positions():
|
||||
"""Calculate and reserve Static Tekton positions early."""
|
||||
if not multiplayer.is_server(): return
|
||||
@@ -803,12 +812,12 @@ func _create_static_setup(pos: Vector2i, tekton_id: int, shape_idx: int):
|
||||
# Position Stand
|
||||
if enhanced_gridmap:
|
||||
# Convert grid to world
|
||||
var world_pos = Vector3(pos.x + 0.5, 0, pos.y + 0.5)
|
||||
var world_pos = Vector3(pos.x + 0.5, 0, pos.y + 0.5)
|
||||
if "cell_size" in enhanced_gridmap:
|
||||
world_pos = Vector3(
|
||||
pos.x * enhanced_gridmap.cell_size.x + enhanced_gridmap.cell_size.x/2,
|
||||
0,
|
||||
pos.y * enhanced_gridmap.cell_size.z + enhanced_gridmap.cell_size.z/2
|
||||
pos.x * enhanced_gridmap.cell_size.x + enhanced_gridmap.cell_size.x / 2,
|
||||
0,
|
||||
pos.y * enhanced_gridmap.cell_size.z + enhanced_gridmap.cell_size.z / 2
|
||||
)
|
||||
stand.global_position = world_pos
|
||||
|
||||
@@ -843,7 +852,6 @@ func _create_static_setup(pos: Vector2i, tekton_id: int, shape_idx: int):
|
||||
_create_tekton(pos, tekton_id, true)
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Player Management
|
||||
# =============================================================================
|
||||
@@ -980,6 +988,13 @@ func sync_game_start(player_list: Array, is_turn_based: bool):
|
||||
TurnManager.turn_based_mode = is_turn_based
|
||||
GameStateManager.start_game()
|
||||
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
if not stop_n_go_manager:
|
||||
stop_n_go_manager = load("res://scripts/managers/stop_n_go_manager.gd").new()
|
||||
stop_n_go_manager.name = "StopNGoManager"
|
||||
add_child(stop_n_go_manager)
|
||||
stop_n_go_manager.activate_client_side()
|
||||
|
||||
# Initialize leaderboard for all peers (after a delay to ensure players loaded)
|
||||
call_deferred("_deferred_init_leaderboard")
|
||||
|
||||
@@ -1354,6 +1369,9 @@ func sync_grid_item(x: int, y: int, z: int, item: int):
|
||||
# For simplicity, we trust the grid syncs via normal mechanisms or initial state.
|
||||
|
||||
func randomize_game_grid():
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
return # Stop n Go manages its own arena setup
|
||||
|
||||
var enhanced_gridmap = $EnhancedGridMap
|
||||
if enhanced_gridmap:
|
||||
# Randomize Floor 1 using ScarcityController
|
||||
@@ -1364,6 +1382,19 @@ func randomize_game_grid():
|
||||
# For now, let's assume server authority + sync on connect handles it, or add sync loop if critical.
|
||||
pass
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func sync_full_grid_data_stop_n_go(floor0: PackedInt32Array, floor1: PackedInt32Array, cols: int, rows: int):
|
||||
print("[Main] Stop n Go Sync: Changing grid size to %dx%d" % [cols, rows])
|
||||
var gridmap = $EnhancedGridMap
|
||||
if gridmap:
|
||||
gridmap.columns = cols
|
||||
gridmap.rows = rows
|
||||
gridmap.clear()
|
||||
gridmap.set_floor_data(0, floor0)
|
||||
gridmap.set_floor_data(1, floor1)
|
||||
gridmap.update_grid_data()
|
||||
gridmap.initialize_astar()
|
||||
|
||||
@rpc("any_peer")
|
||||
func request_full_grid_sync():
|
||||
if multiplayer.is_server():
|
||||
@@ -1382,7 +1413,7 @@ func request_full_grid_sync():
|
||||
func sync_full_grid_data(data: PackedInt32Array):
|
||||
print("[Main] sync_full_grid_data received. Items: %d" % (data.size() / 3))
|
||||
var enhanced_gridmap = $EnhancedGridMap
|
||||
if not enhanced_gridmap:
|
||||
if not enhanced_gridmap:
|
||||
print("[Main] Error: EnhancedGridMap not found!")
|
||||
return
|
||||
|
||||
@@ -1459,6 +1490,23 @@ func _on_global_timer_updated(time_remaining: float):
|
||||
var minutes = int(time_remaining) / 60
|
||||
var seconds = int(time_remaining) % 60
|
||||
timer_label.text = "%d:%02d" % [minutes, seconds]
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func sync_game_end_stop_n_go(winner_id: int):
|
||||
print("[STOP n GO] Game ended! Winner: ", 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("WINNER", winner_name + " Reached the Finish Line!", MessageType.GOAL)
|
||||
|
||||
# Stop logic
|
||||
if stop_n_go_manager:
|
||||
stop_n_go_manager.is_active = false
|
||||
|
||||
# Trigger match end
|
||||
_on_match_ended()
|
||||
|
||||
func _on_match_ended():
|
||||
"""Called when the global match timer ends - show game over screen."""
|
||||
@@ -1555,7 +1603,7 @@ func _show_game_over_panel():
|
||||
Color(0.5, 0.5, 0.5), # 5th
|
||||
Color(0.5, 0.5, 0.5), # 6th
|
||||
Color(0.5, 0.5, 0.5), # 7th
|
||||
Color(0.5, 0.5, 0.5) # 8th
|
||||
Color(0.5, 0.5, 0.5) # 8th
|
||||
]
|
||||
var rank_emojis = ["🥇", "🥈", "🥉", "4th", "5th", "6th", "7th", "8th"]
|
||||
|
||||
@@ -1723,7 +1771,6 @@ func _render_leaderboard_entries(sorted_player_data: Array):
|
||||
# If local player is outside top 3 (index > 2), show them in 4th slot
|
||||
# But if they are exactly 4th (index 3), it's the same as showing 4th place.
|
||||
# If they are 5th (index 4) or worse, we replace 4th place with them.
|
||||
|
||||
if my_index > 3:
|
||||
# Show local player
|
||||
items_to_display.append({"data": sorted_player_data[my_index], "rank": my_index + 1})
|
||||
|
||||
@@ -832,6 +832,67 @@ func _find_valid_drop_position() -> Vector2i:
|
||||
|
||||
return Vector2i(-1, -1)
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func on_stop_phase_violation():
|
||||
"""Moving during STOP phase makes you lose and scatter tiles."""
|
||||
if not multiplayer.is_server(): return
|
||||
|
||||
print("[STOP n GO] Violation by player %s! Scattering tiles." % name)
|
||||
|
||||
# Stun effect
|
||||
apply_stagger(2.0)
|
||||
|
||||
# Scatter items
|
||||
var items_to_scatter = []
|
||||
for i in range(playerboard.size()):
|
||||
if playerboard[i] != -1:
|
||||
items_to_scatter.append(playerboard[i])
|
||||
playerboard[i] = -1
|
||||
|
||||
if items_to_scatter.is_empty():
|
||||
return
|
||||
|
||||
rpc("sync_playerboard", playerboard)
|
||||
|
||||
# Find multiple valid drop positions around the player
|
||||
var drop_positions = _find_multiple_drop_positions(items_to_scatter.size())
|
||||
|
||||
for i in range(items_to_scatter.size()):
|
||||
var item_id = items_to_scatter[i]
|
||||
var pos = drop_positions[i] if i < drop_positions.size() else _find_valid_drop_position()
|
||||
|
||||
if pos != Vector2i(-1, -1):
|
||||
var cell = Vector3i(pos.x, 1, pos.y)
|
||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, item_id)
|
||||
|
||||
NotificationManager.send_message(self, "STOP VIOLATION! Tiles scattered!", NotificationManager.MessageType.WARNING)
|
||||
|
||||
func _find_multiple_drop_positions(count: int) -> Array:
|
||||
var positions = []
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
neighbors.shuffle()
|
||||
|
||||
# Also consider neighbors of neighbors (radius 2) for more scattering
|
||||
var candidates = []
|
||||
for n in neighbors:
|
||||
candidates.append(n.position)
|
||||
var n2 = enhanced_gridmap.get_neighbors(n.position, 0)
|
||||
for nn in n2:
|
||||
if not nn.position in candidates:
|
||||
candidates.append(nn.position)
|
||||
|
||||
candidates.shuffle()
|
||||
|
||||
for pos in candidates:
|
||||
if positions.size() >= count: break
|
||||
|
||||
var item_cell = Vector3i(pos.x, 1, pos.y)
|
||||
if enhanced_gridmap.get_cell_item(item_cell) == -1:
|
||||
if not is_position_occupied(pos):
|
||||
positions.append(pos)
|
||||
|
||||
return positions
|
||||
|
||||
# =============================================================================
|
||||
# Targeting Action
|
||||
# =============================================================================
|
||||
@@ -1200,6 +1261,15 @@ func start_movement_along_path(path: Array, clear_visual: bool = true):
|
||||
if is_carrying_tekton and is_instance_valid(carried_tekton):
|
||||
carried_tekton.current_position = current_position
|
||||
|
||||
# Stop n Go Win Check
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
var sng_main = get_tree().root.get_node_or_null("Main")
|
||||
if sng_main:
|
||||
var sng_manager = sng_main.get_node_or_null("StopNGoManager")
|
||||
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())
|
||||
|
||||
# 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)
|
||||
|
||||
Reference in New Issue
Block a user