feat: Add initial main game scene with grid map, player board UI, and manager scripts for game logic and input.
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="tekton-local"
|
config/name="tekton-local"
|
||||||
run/main_scene="uid://dxn87yj8qnfpp"
|
run/main_scene="uid://b7nxt2hc4kqp8"
|
||||||
config/features=PackedStringArray("4.6", "Forward Plus")
|
config/features=PackedStringArray("4.6", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -9787,7 +9787,7 @@ offset_right = -73.0
|
|||||||
offset_bottom = -171.0
|
offset_bottom = -171.0
|
||||||
grow_horizontal = 0
|
grow_horizontal = 0
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
text = "⚡"
|
text = "🚀"
|
||||||
|
|
||||||
[node name="SettingsBtn" type="Button" parent="TouchControls/TouchControls" unique_id=1964422444]
|
[node name="SettingsBtn" type="Button" parent="TouchControls/TouchControls" unique_id=1964422444]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
|||||||
@@ -119,11 +119,13 @@ func _execute_grab(grid_pos: Vector2i, cell: Vector3i, item_id: int):
|
|||||||
# Check if item is still there
|
# Check if item is still there
|
||||||
if server_item != item_id:
|
if server_item != item_id:
|
||||||
print("Server: Item mismatch or already taken. Server has ", server_item)
|
print("Server: Item mismatch or already taken. Server has ", server_item)
|
||||||
|
_force_sync_to_client(cell, server_item)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Check action points
|
# Check action points
|
||||||
if player.action_points <= 0:
|
if player.action_points <= 0:
|
||||||
print("Server: Player has no action points.")
|
print("Server: Player has no action points.")
|
||||||
|
_force_sync_to_client(cell, server_item)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Check adjacency
|
# Check adjacency
|
||||||
@@ -131,12 +133,14 @@ func _execute_grab(grid_pos: Vector2i, cell: Vector3i, item_id: int):
|
|||||||
var neighbors = server_gridmap.get_neighbors(player.current_position, 0)
|
var neighbors = server_gridmap.get_neighbors(player.current_position, 0)
|
||||||
if not neighbors.any(func(n): return n.position == grid_pos):
|
if not neighbors.any(func(n): return n.position == grid_pos):
|
||||||
print("Server: Player is not adjacent to item.")
|
print("Server: Player is not adjacent to item.")
|
||||||
|
_force_sync_to_client(cell, server_item)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# 2. Server-side Auto-Arrange
|
# 2. Server-side Auto-Arrange
|
||||||
var target_slot = find_best_goal_slot_for_item(item_id)
|
var target_slot = find_best_goal_slot_for_item(item_id)
|
||||||
if target_slot == -1:
|
if target_slot == -1:
|
||||||
print("Server: Player has no valid slot for item.")
|
print("Server: Player has no valid slot for item.")
|
||||||
|
_force_sync_to_client(cell, server_item)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# 3. Server Executes the Action
|
# 3. Server Executes the Action
|
||||||
@@ -197,6 +201,32 @@ func _check_and_refill_grid_if_needed(server_gridmap: Node):
|
|||||||
var item = server_gridmap.get_cell_item(Vector3i(x, 1, z))
|
var item = server_gridmap.get_cell_item(Vector3i(x, 1, z))
|
||||||
main.rpc("sync_grid_item", x, 1, z, item)
|
main.rpc("sync_grid_item", x, 1, z, item)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _force_sync_to_client(cell: Vector3i, server_item: int):
|
||||||
|
"""Force a sync of the specific cell and playerboard to the client who initiated the failed action."""
|
||||||
|
# Only meaningful if we are server
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
|
||||||
|
var main = player.get_tree().get_root().get_node_or_null("Main")
|
||||||
|
if not main: return
|
||||||
|
|
||||||
|
# Determine client peer ID from player name (standard convention)
|
||||||
|
# Note: Bots are ID 1, so we don't need to sync special for them (local function calls)
|
||||||
|
# But for Clients...
|
||||||
|
var peer_id = player.name.to_int()
|
||||||
|
if peer_id == 1: # Server/Bot
|
||||||
|
return
|
||||||
|
|
||||||
|
# Sync the Grid Item (which they thought they took)
|
||||||
|
main.rpc_id(peer_id, "sync_grid_item", cell.x, cell.y, cell.z, server_item)
|
||||||
|
|
||||||
|
# Sync their Playerboard (which they thought they updated)
|
||||||
|
main.rpc_id(peer_id, "sync_playerboard", peer_id, player.playerboard)
|
||||||
|
|
||||||
|
print("Server: Forced sync to client %d due to action failure." % peer_id)
|
||||||
|
|
||||||
func bot_try_grab_item() -> bool:
|
func bot_try_grab_item() -> bool:
|
||||||
if not enhanced_gridmap or player.action_points <= 0:
|
if not enhanced_gridmap or player.action_points <= 0:
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func _on_boost_full():
|
|||||||
# player.is_attack_mode = true # Removed auto-activate
|
# player.is_attack_mode = true # Removed auto-activate
|
||||||
emit_signal("bar_filled")
|
emit_signal("bar_filled")
|
||||||
NotificationManager.send_message(player, NotificationManager.MESSAGES.ATTACK_MODE_READY, NotificationManager.MessageType.POWERUP)
|
NotificationManager.send_message(player, NotificationManager.MESSAGES.ATTACK_MODE_READY, NotificationManager.MessageType.POWERUP)
|
||||||
print("[PowerUp] Player %s Boost Full! Entering Attack Mode." % player.name)
|
print("[PowerUp] Player %s Boost Full! Ready for Attack Mode." % player.name)
|
||||||
|
|
||||||
if player.is_multiplayer_authority():
|
if player.is_multiplayer_authority():
|
||||||
rpc("sync_boost", current_boost)
|
rpc("sync_boost", current_boost)
|
||||||
@@ -100,6 +100,14 @@ func sync_boost(value: float):
|
|||||||
# Could trigger visual effect here
|
# Could trigger visual effect here
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func sync_boost_level(level: int):
|
||||||
|
current_level = level
|
||||||
|
var level_idx = clamp(current_level - 1, 0, FILL_TIMES.size() - 1)
|
||||||
|
print("[PowerUp] Difficulty synced: Level %d (Fill Time: %.1fs)" % [current_level, FILL_TIMES[level_idx]])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Getters
|
# Getters
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -113,6 +121,11 @@ func get_max_points() -> int:
|
|||||||
func get_fill_percentage() -> float:
|
func get_fill_percentage() -> float:
|
||||||
return current_boost / MAX_BOOST
|
return current_boost / MAX_BOOST
|
||||||
|
|
||||||
|
func get_bars() -> int:
|
||||||
|
"""Returns the number of filled segments (0-4)."""
|
||||||
|
# Each bar is 25 points (100 / 4)
|
||||||
|
return int(current_boost / 25.0)
|
||||||
|
|
||||||
func can_use_special() -> bool:
|
func can_use_special() -> bool:
|
||||||
# Use small epsilon for float comparison to avoid "99.999" issues
|
# Use small epsilon for float comparison to avoid "99.999" issues
|
||||||
return current_boost >= (MAX_BOOST - 0.1)
|
return current_boost >= (MAX_BOOST - 0.1)
|
||||||
@@ -177,3 +190,7 @@ func add_goal_completion_reward():
|
|||||||
print("[PowerUp] Player %s Completed Goal. Boost Level Up! Now: %d (Fill Time: %.1fs)" % [player.name, current_level, FILL_TIMES[level_idx]])
|
print("[PowerUp] Player %s Completed Goal. Boost Level Up! Now: %d (Fill Time: %.1fs)" % [player.name, current_level, FILL_TIMES[level_idx]])
|
||||||
|
|
||||||
# Optional: Notify user of difficulty increase?
|
# Optional: Notify user of difficulty increase?
|
||||||
|
|
||||||
|
if multiplayer.is_server():
|
||||||
|
rpc("sync_boost_level", current_level)
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,9 @@ func _style_button(btn: Button, opacity: float):
|
|||||||
|
|
||||||
btn.add_theme_font_size_override("font_size", 28)
|
btn.add_theme_font_size_override("font_size", 28)
|
||||||
|
|
||||||
|
# Prevent buttons from stealing focus (fixes Spacebar activation)
|
||||||
|
btn.focus_mode = Control.FOCUS_NONE
|
||||||
|
|
||||||
func _on_joystick_direction(direction: Vector2i):
|
func _on_joystick_direction(direction: Vector2i):
|
||||||
if local_player and local_player.has_method("simple_move_to"):
|
if local_player and local_player.has_method("simple_move_to"):
|
||||||
var target_pos = local_player.current_position + direction
|
var target_pos = local_player.current_position + direction
|
||||||
|
|||||||
Reference in New Issue
Block a user