extends Node var player: Node3D var movement_manager: Node var race_manager: Node @onready var SettingsManager = get_node_or_null("/root/SettingsManager") func initialize(p_player: Node3D, p_movement_manager: Node, p_race_manager: Node): player = p_player movement_manager = p_movement_manager race_manager = p_race_manager func _process(delta): # Early return conditions if not is_instance_valid(player) or not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots") or player.is_frozen or player.is_stop_frozen: return if TurnManager.turn_based_mode: return # Continuous movement input var move_vec = Vector2i.ZERO if Input.is_action_pressed("move_north"): move_vec.y -= 1 if Input.is_action_pressed("move_south"): move_vec.y += 1 if Input.is_action_pressed("move_east"): move_vec.x += 1 if Input.is_action_pressed("move_west"): move_vec.x -= 1 # Fallback for explicit diagonal actions (if mapped) if move_vec == Vector2i.ZERO: if Input.is_action_pressed("move_northeast"): move_vec = Vector2i(1, -1) elif Input.is_action_pressed("move_southeast"): move_vec = Vector2i(1, 1) elif Input.is_action_pressed("move_southwest"): move_vec = Vector2i(-1, 1) elif Input.is_action_pressed("move_northwest"): move_vec = Vector2i(-1, -1) # Action inputs (still momentary) if Input.is_action_just_pressed("action_grab"): player.grab_item(player.current_position) elif Input.is_action_just_pressed("action_put"): player.auto_put_item() if move_vec != Vector2i.ZERO: var target_position = player.current_position + move_vec movement_manager.simple_move_to(target_position) # Targeting Mode Preview var main = player.get_node_or_null("/root/Main") if main and main.ui_manager and main.ui_manager.current_action_state == main.ui_manager.ActionState.TARGETING: # Use mouse position raycast to determine hover var viewport = player.get_viewport() var mouse_pos = viewport.get_mouse_position() var camera = viewport.get_camera_3d() var from = camera.project_ray_origin(mouse_pos) var to = from + camera.project_ray_normal(mouse_pos) * 1000 var hover_grid = player.raycast_to_grid(from, to) # print("Targeting Hover: %s, Skill: %d" % [hover_grid, main.ui_manager.pending_skill_id]) # Debug # Only update if valid position if hover_grid != Vector2i(-1, -1): var st_manager = player.get_node_or_null("SpecialTilesManager") if st_manager: var area = st_manager.get_skill_affected_area(main.ui_manager.pending_skill_id, hover_grid) # Choose highlight color/mesh based on skill # User Request: Use default hover item (1) var highlight_id = 1 player.highlight_cells_if_authorized(area, highlight_id) func handle_unhandled_input(event): # Early return if not authorized human playersa if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"): player.set_process_unhandled_input(false) return var main = player.get_node("/root/Main") if not main: return # Turn-based mouse input (handled in unhandled_input) if not player.is_multiplayer_authority() or player.is_frozen or player.is_stop_frozen or (TurnManager.turn_based_mode and (not player.is_my_turn or movement_manager.is_moving)): return # --- Keyboard Shortcuts (Event-based) --- if event is InputEventKey and event.pressed and not event.echo: var mode = LobbyManager.get_game_mode() var is_sng = mode == GameMode.Mode.STOP_N_GO # Get dynamic keybinds var key_p1 = SettingsManager.get_control_keycode("powerup_1") var key_p2 = SettingsManager.get_control_keycode("powerup_2") var key_p3 = SettingsManager.get_control_keycode("powerup_3") var key_p4 = SettingsManager.get_control_keycode("powerup_4") var ek = event.keycode # Unified check for PowerUp keys if ek == key_p1: player.activate_powerup(0) # FASTER_SPEED elif ek == key_p2: if is_sng: player.activate_powerup(3) # Ghost for SNG P2 else: player.activate_powerup(2) # Wall for Normal P2 elif ek == key_p3 and not is_sng: player.activate_powerup(1) # AREA_FREEZE elif ek == key_p4 and not is_sng: player.activate_powerup(3) # INVISIBLE_MODE # Non-Remappable variants (Numpad) - Optional fallback elif ek == KEY_KP_1: player.activate_powerup(0) elif ek == KEY_KP_2: player.activate_powerup(3 if is_sng else 2) # Action Buttons (Remappable) elif ek == SettingsManager.get_control_keycode("attack_mode"): if player.powerup_manager: player.powerup_manager.use_special_effect() if player.is_attack_mode and player.has_method("enter_attack_mode"): player.enter_attack_mode() elif ek == SettingsManager.get_control_keycode("spawn_boost"): if player.is_carrying_tekton and player.powerup_manager: if player.powerup_manager.has_method("spawn_boost_reward"): player.powerup_manager.spawn_boost_reward() elif ek == SettingsManager.get_control_keycode("tekton_grab"): if not player.is_carrying_tekton and player.powerup_manager: if player.powerup_manager.can_use_special(): player.grab_tekton() # Handle spawn point selection if not yet selected # Handle spawn point selection if not yet selected if not player.spawn_point_selected and player.highlighted_spawn_points.size() > 0: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: var camera = player.get_viewport().get_camera_3d() var from = camera.project_ray_origin(event.position) var to = from + camera.project_ray_normal(event.position) * 1000 var click_position = player.raycast_to_grid(from, to) if click_position in player.highlighted_spawn_points: if player.select_spawn_point(click_position): return # Turn-based mouse input if not player.is_multiplayer_authority() or (TurnManager.turn_based_mode and (not player.is_my_turn or movement_manager.is_moving)): return if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: if player.is_bot == true or player.is_in_group("Bots"): player.set_process_unhandled_input(false) player.set_process_input(false) return var camera = player.get_viewport().get_camera_3d() var from = camera.project_ray_origin(event.position) var to = from + camera.project_ray_normal(event.position) * 1000 var click_position = player.raycast_to_grid(from, to) if click_position != Vector2i(-1, -1): handle_grid_click(click_position) func handle_grid_click(grid_position: Vector2i): if player.is_frozen or player.is_stop_frozen or player.is_bot == true or player.is_in_group("Bots"): return var main = player.get_node("/root/Main") if not main: return match main.ui_manager.current_action_state: main.ui_manager.ActionState.MOVING: if grid_position in player.highlighted_cells: movement_manager.move_to_clicked_position(grid_position) main.ui_manager.ActionState.GRABBING: if grid_position in player.highlighted_cells or grid_position == player.current_position: player.grab_item(grid_position) main.ui_manager.ActionState.RANDOMIZING: if grid_position in player.highlighted_cells: main.randomize_item_at_position(grid_position) # Add TARGETING State main.ui_manager.ActionState.TARGETING: var skill_id = main.ui_manager.pending_skill_id if skill_id != -1: var st_manager = player.get_node_or_null("SpecialTilesManager") if st_manager: # Clear Highlights FIRST to avoid overwriting the newly placed tiles player.clear_highlights() st_manager.execute_targeted_effect(skill_id, grid_position) # Reset state main.ui_manager.pending_skill_id = -1 main.ui_manager.current_action_state = main.ui_manager.ActionState.NONE func handle_slot_gui_input(event, slot_index, slot_ui) -> int: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: var main = player.get_tree().get_root().get_node_or_null("Main") if main.ui_manager.current_action_state == main.ui_manager.ActionState.ARRANGING: if player.selected_playerboard_slot == -1: player.select_playerboard_slot(slot_index) return slot_index else: if player.selected_playerboard_slot == slot_index: player.deselect_playerboard_slot() return slot_index elif player.can_move_to_target_playerboard_slot(): player.target_playerboard_slot(slot_index) main.emit_signal("can_move_item", true) return slot_index else: return -1 return -1