feat: Implement core playerboard management including item grabbing, power-up handling, goal completion, and grid refilling, alongside new Tekton entity and various game managers.
This commit is contained in:
@@ -27,7 +27,6 @@ AuthManager="*res://scripts/managers/auth_manager.gd"
|
||||
LobbyManager="*res://scripts/managers/lobby_manager.gd"
|
||||
UserProfileManager="*res://scripts/managers/user_profile_manager.gd"
|
||||
GameStateManager="*res://scripts/managers/game_state_manager.gd"
|
||||
NetworkManager="*res://scripts/network_manager.gd"
|
||||
TurnManager="*res://scripts/managers/turn_manager.gd"
|
||||
GoalManager="*res://scripts/managers/goal_manager.gd"
|
||||
PlayerManager="*res://scripts/managers/player_manager.gd"
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
[ext_resource type="Script" uid="uid://dyovwailce5tf" path="res://scripts/tekton.gd" id="1_tekton"]
|
||||
[ext_resource type="Script" uid="uid://c67yq846u8y68" path="res://scripts/tekton_controller.gd" id="2_controller"]
|
||||
[ext_resource type="PackedScene" uid="uid://b6d6qu1ir13q1" path="res://scenes/tekton_mesh.scn" id="3_d2kpk"]
|
||||
[ext_resource type="PackedScene" uid="uid://b6d6qu1ir13q1" path="res://scenes/tekton_mesh.tscn" id="3_d2kpk"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_tekton"]
|
||||
size = Vector3(0.8, 1, 0.8)
|
||||
|
||||
@@ -58,8 +58,14 @@ func _ready():
|
||||
queue_free()
|
||||
return
|
||||
|
||||
# Wait for actor to be fully ready (player._ready awaits 0.5s then creates managers)
|
||||
await get_tree().create_timer(1.5).timeout
|
||||
# Wait for actor to be fully ready (poll for EnhancedGridMap)
|
||||
var wait_timeout = 3.0
|
||||
var wait_elapsed = 0.0
|
||||
while wait_elapsed < wait_timeout:
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
wait_elapsed += 0.1
|
||||
if actor and actor.get("enhanced_gridmap") and actor.enhanced_gridmap:
|
||||
break
|
||||
|
||||
enhanced_gridmap = actor.enhanced_gridmap
|
||||
if not enhanced_gridmap:
|
||||
@@ -107,7 +113,7 @@ func _physics_process(delta):
|
||||
|
||||
# Rate limiting (with difficulty scaling for Stop n Go)
|
||||
var current_tick_rate = tick_rate
|
||||
if LobbyManager.game_mode == "Stop n Go" and actor.current_position.x > 10:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and actor.current_position.x > 10:
|
||||
current_tick_rate = int(tick_rate * 0.6) # 40% faster updates after column 10
|
||||
|
||||
_tick_counter += 1
|
||||
@@ -133,7 +139,7 @@ func _run_ai_tick():
|
||||
return
|
||||
|
||||
# STOP N GO: Don't process if already at finish line
|
||||
if LobbyManager.game_mode == "Stop n Go" and actor.current_position.x >= 21:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and actor.current_position.x >= 21:
|
||||
return
|
||||
|
||||
# STOP N GO: Red light freezing logic
|
||||
@@ -150,7 +156,7 @@ func _run_ai_tick():
|
||||
print("[BotController] %s AI Tick. Goals: %s, Fullness: %.2f" % [actor.name, actor.goals, board_fullness])
|
||||
|
||||
# 0. BOT AGGRESSION THRESHOLD (Stop n Go)
|
||||
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
var can_be_aggressive = not is_sng or actor.current_position.x > 10
|
||||
|
||||
# PRIORITY OVERRIDE: If board is getting full, prioritize clearing space!
|
||||
@@ -289,7 +295,7 @@ func _try_attack_chase() -> bool:
|
||||
var next_step = Vector2i(path[1].x, path[1].y)
|
||||
|
||||
# STOP N GO BOUNDARY PROTECTION
|
||||
if LobbyManager.game_mode == "Stop n Go" and next_step.x >= 21:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and next_step.x >= 21:
|
||||
var main = get_tree().root.get_node_or_null("Main")
|
||||
var gc_manager = main.get_node_or_null("GoalsCycleManager") if main else null
|
||||
var time_remaining = gc_manager.get_global_time_remaining() if gc_manager else 999.0
|
||||
@@ -683,7 +689,7 @@ func _get_board_fullness_ratio() -> float:
|
||||
|
||||
func _is_goals_achieved() -> bool:
|
||||
"""Check if goal pattern is complete (Standard) or mission complete (Stop n Go)."""
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO):
|
||||
var main = get_tree().root.get_node_or_null("Main")
|
||||
if main:
|
||||
var sng_manager = main.get_node_or_null("StopNGoManager")
|
||||
|
||||
@@ -255,7 +255,7 @@ func find_nearest_tile_of_type(tile_types: Array) -> Vector2i:
|
||||
var found_in_layer = []
|
||||
|
||||
# In Stop n Go, prefer tiles "ahead" (higher X)
|
||||
var is_stop_n_go = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_stop_n_go = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
|
||||
# Check the ring
|
||||
for x_off in range(-r, r + 1):
|
||||
@@ -311,7 +311,7 @@ func _check_spiral_cell(x: int, z: int, tile_types: Array, result_array: Array):
|
||||
func find_optimal_move_target() -> Vector2i:
|
||||
"""Calculate the best position to move towards."""
|
||||
var main = actor.get_tree().get_root().get_node_or_null("Main")
|
||||
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
var gc_manager = main.get_node_or_null("GoalsCycleManager") if main else null
|
||||
var time_left = gc_manager.get_global_time_remaining() if gc_manager else 999.0
|
||||
var is_match_running = gc_manager.is_match_running() if gc_manager else false
|
||||
@@ -521,7 +521,7 @@ func evaluate_sabotage_opportunity() -> Dictionary:
|
||||
return result
|
||||
|
||||
# 0. STOP N GO THRESHOLD: No sabotage until passing column 10
|
||||
if LobbyManager.game_mode == "Stop n Go" and actor.current_position.x <= 10:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and actor.current_position.x <= 10:
|
||||
return result
|
||||
|
||||
# Get opponents
|
||||
@@ -540,7 +540,7 @@ func evaluate_sabotage_opportunity() -> Dictionary:
|
||||
|
||||
# Condition 2: Opponent is close to completing their goal
|
||||
var progress_threshold = 0.7
|
||||
if LobbyManager.game_mode == "Stop n Go" and actor.current_position.x > 10:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and actor.current_position.x > 10:
|
||||
progress_threshold = 0.4 # More aggressive in late game!
|
||||
|
||||
for opponent in opponents:
|
||||
@@ -563,7 +563,7 @@ func evaluate_sabotage_opportunity() -> Dictionary:
|
||||
return result
|
||||
|
||||
# Condition 4: Random Aggression (Stop n Go Late Game)
|
||||
if LobbyManager.game_mode == "Stop n Go" and actor.current_position.x > 12:
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO) and actor.current_position.x > 12:
|
||||
if randf() < 0.3: # 30% chance each tick to just be mean
|
||||
result.should_sabotage = true
|
||||
result.reason = "random_aggression"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
class_name GameMode extends RefCounted
|
||||
|
||||
enum Mode {
|
||||
FREEMODE = 0,
|
||||
STOP_N_GO = 1,
|
||||
TEKTON_DOORS = 2
|
||||
}
|
||||
|
||||
static func from_string(mode: String) -> Mode:
|
||||
match mode:
|
||||
"Freemode":
|
||||
return Mode.FREEMODE
|
||||
"Stop n Go":
|
||||
return Mode.STOP_N_GO
|
||||
"Tekton Doors":
|
||||
return Mode.TEKTON_DOORS
|
||||
_:
|
||||
return Mode.FREEMODE
|
||||
|
||||
static func mode_to_string(mode: Mode) -> String:
|
||||
match mode:
|
||||
Mode.FREEMODE:
|
||||
return "Freemode"
|
||||
Mode.STOP_N_GO:
|
||||
return "Stop n Go"
|
||||
Mode.TEKTON_DOORS:
|
||||
return "Tekton Doors"
|
||||
_:
|
||||
return "Freemode"
|
||||
|
||||
static func is_restricted(mode: Mode) -> bool:
|
||||
return mode == Mode.STOP_N_GO or mode == Mode.TEKTON_DOORS
|
||||
|
||||
static func get_all_modes() -> Array[String]:
|
||||
return ["Freemode", "Stop n Go", "Tekton Doors"]
|
||||
@@ -0,0 +1 @@
|
||||
uid://cx8k9m2p5yqjw
|
||||
@@ -75,9 +75,10 @@ func _update_camera_target():
|
||||
var current_row = player.current_position.y
|
||||
var current_col = player.current_position.x
|
||||
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
if mode == GameMode.Mode.STOP_N_GO:
|
||||
_update_stop_n_go_camera(current_row, current_col)
|
||||
elif LobbyManager.game_mode == "Tekton Doors":
|
||||
elif mode == GameMode.Mode.TEKTON_DOORS:
|
||||
_update_tekton_doors_camera()
|
||||
else:
|
||||
_update_freemode_camera(current_row, current_col)
|
||||
|
||||
@@ -46,6 +46,12 @@ var selected_area: String = "Desert" # Host-controlled
|
||||
var game_mode: String = "Freemode" # Host-controlled
|
||||
var local_character_index: int = 0 # Local player's character index
|
||||
|
||||
func get_game_mode() -> GameMode.Mode:
|
||||
return GameMode.from_string(game_mode)
|
||||
|
||||
func is_game_mode(mode: GameMode.Mode) -> bool:
|
||||
return get_game_mode() == mode
|
||||
|
||||
# Signals
|
||||
signal game_mode_changed(mode: String)
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ func handle_unhandled_input(event):
|
||||
if event is InputEventKey and event.pressed and not event.echo:
|
||||
match event.keycode:
|
||||
KEY_KP_1, KEY_1, KEY_KP_2, KEY_2, KEY_KP_3, KEY_3, KEY_KP_4, KEY_4:
|
||||
var is_restricted = LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors"
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
match event.keycode:
|
||||
KEY_KP_1, KEY_1:
|
||||
player.activate_powerup(0) # FASTER_SPEED
|
||||
|
||||
@@ -219,7 +219,7 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
|
||||
|
||||
# SCORING: 200 Points for successful attack (ONLY in Free Mode)
|
||||
if player.is_multiplayer_authority():
|
||||
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
if not is_sng:
|
||||
var main = player.get_tree().get_root().get_node_or_null("Main")
|
||||
if main:
|
||||
|
||||
@@ -232,7 +232,7 @@ func _check_and_refill_grid_if_needed(server_gridmap: Node):
|
||||
break
|
||||
|
||||
if not has_items:
|
||||
if LobbyManager.game_mode == "Tekton Doors":
|
||||
if LobbyManager.is_game_mode(GameMode.Mode.TEKTON_DOORS):
|
||||
# Tekton Doors handles its own wall-aware refill in PortalModeManager
|
||||
return
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ func _execute_area_freeze(center_pos: Vector2i = Vector2i.ZERO):
|
||||
hit_count += 1
|
||||
|
||||
if hit_count > 0 and player.is_multiplayer_authority():
|
||||
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
if not is_sng:
|
||||
var points = hit_count * 50
|
||||
var main = player.get_tree().get_root().get_node_or_null("Main")
|
||||
@@ -462,7 +462,8 @@ func spawn_powerups_around(center: Vector2i, force_powerups: bool = true):
|
||||
item_id = rng.randi_range(7, 10)
|
||||
else:
|
||||
# 30% Chance for PowerUp (Speed 11, Freeze 12, Ghost 14 - Exclude Wall 13 in restricted modes)
|
||||
var is_restricted = LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors"
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
if is_restricted:
|
||||
item_id = [11, 12, 14].pick_random()
|
||||
else:
|
||||
|
||||
@@ -256,7 +256,7 @@ func _ensure_shortcut_label(btn: Button, button_name: String):
|
||||
if btn.has_node("ShortcutLabel"):
|
||||
# Update Label content if it exists to match potential remapping
|
||||
var existing_lbl = btn.get_node("ShortcutLabel")
|
||||
var is_sng = LobbyManager.game_mode == "Stop n Go"
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
|
||||
match button_name:
|
||||
"Grab": existing_lbl.text = "Space" if is_sng else ""
|
||||
|
||||
@@ -50,7 +50,8 @@ static func get_tile_weights() -> Dictionary:
|
||||
weights[tile] = STANDARD_WEIGHT
|
||||
|
||||
# Special tiles
|
||||
var is_restricted = LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors"
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
for tile in SPECIAL_TILES:
|
||||
if is_restricted and tile == TILE_WALL:
|
||||
continue # Hide Wall Block only in restricted modes
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
extends Node
|
||||
|
||||
# This script is deprecated in favor of NakamaManager.
|
||||
# The logic has been moved to allow the NakamaMultiplayerBridge to handle
|
||||
# the networking transparently.
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func host_game():
|
||||
# Redirect to NakamaManager
|
||||
NakamaManager.host_game()
|
||||
|
||||
func join_game(match_id):
|
||||
# Redirect to NakamaManager
|
||||
NakamaManager.join_game(match_id)
|
||||
@@ -1 +0,0 @@
|
||||
uid://l4qd7n8l2hch
|
||||
@@ -32,7 +32,8 @@ func _ready():
|
||||
var wall_btn = container.get_node_or_null("WallBtn")
|
||||
_setup_btn(2, wall_btn)
|
||||
|
||||
var is_restricted = LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors"
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
if wall_btn and is_restricted:
|
||||
wall_btn.visible = false # Hide Wall Power-up in restricted modes
|
||||
_setup_btn(3, container.get_node_or_null("GhostBtn"))
|
||||
@@ -104,7 +105,8 @@ func _setup_btn(effect_id: int, btn: Button):
|
||||
|
||||
# Determine Label Text based on Effect ID
|
||||
var key_text = ""
|
||||
var is_restricted = LobbyManager.game_mode == "Stop n Go" or LobbyManager.game_mode == "Tekton Doors"
|
||||
var mode = LobbyManager.get_game_mode()
|
||||
var is_restricted = GameMode.is_restricted(mode)
|
||||
if is_restricted:
|
||||
# Restricted Mapping: 1, 2, 3 (No Wall)
|
||||
match effect_id:
|
||||
|
||||
Reference in New Issue
Block a user