extends Node3D @export var enhanced_gridmap_path: NodePath = "/root/Main/EnhancedGridMap" var enhanced_gridmap: EnhancedGridMap @export var current_position: Vector2i var is_player_moving: bool = false @export var cell_size: Vector3 = Vector3(2, 2, 2) @export var cell_offset: Vector3 = Vector3(0, 0, 0) @export var center_x: bool = false @export var center_y: bool = false @export var center_z: bool = false # Goals & Playerboard Data @export var goals: Array[int] = [0,0,0,0,0,0,0,0,0] # 9 length array for goals @export var playerboard: Array[int] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] # 25 length array for holding items var has_performed_action: bool = false # Track if grab/put action has been done # Player Rotation Config # Add these variables for rotation var target_rotation: float = 0.0 var rotation_speed: float = 10.0 # Adjust this to control rotation speed @export var movement_range: int = 1 # How many blocks can be moved at once @export var use_diagonal_movement: bool = false: # Allow diagonal movement set(value): use_diagonal_movement = value if enhanced_gridmap: enhanced_gridmap.set_diagonal_movement(value) @export var is_my_turn: bool = false: set(value): is_my_turn = value if is_my_turn and is_multiplayer_authority(): rpc("display_message", "It's your turn!") @export var has_moved_this_turn = false @onready var main_scene = get_tree().current_scene func _ready(): name = str(get_multiplayer_authority()) $Name.text = str(name) enhanced_gridmap = get_node(enhanced_gridmap_path) if main_scene: enhanced_gridmap = main_scene.get_node("EnhancedGridMap") else: push_error("Main scene not found") if not enhanced_gridmap: push_error("EnhancedGridMap node not found. Please set the correct path in the inspector.") return enhanced_gridmap.initialize_astar() enhanced_gridmap.set_diagonal_movement(use_diagonal_movement) current_position = find_valid_starting_position() update_player_position(current_position) set_process_unhandled_input(is_multiplayer_authority()) # Initialize random goals initialize_random_goals() # Initialize playerboard with -1 (empty slots) playerboard.resize(25) playerboard.fill(-1) func find_valid_starting_position() -> Vector2i: var rng = RandomNumberGenerator.new() rng.randomize() var max_attempts = 100 var attempts = 0 while attempts < max_attempts: current_position = Vector2i(0, rng.randi_range(0, 9)) var cell_item = enhanced_gridmap.get_cell_item(Vector3i(current_position.x, 0, current_position.y)) if cell_item not in enhanced_gridmap.non_walkable_items: return current_position attempts += 1 return Vector2i(0, 0) func find_random_valid_position_in_range() -> Vector2i: var rng = RandomNumberGenerator.new() rng.randomize() var max_attempts = 100 var attempts = 0 while attempts < max_attempts: var range_x = min(enhanced_gridmap.columns - 1, movement_range) var range_y = min(enhanced_gridmap.rows - 1, movement_range) # Generate position within movement range of current position var offset_x = rng.randi_range(-range_x, range_x) var offset_y = rng.randi_range(-range_y, range_y) var random_position = Vector2i( clamp(current_position.x + offset_x, 0, enhanced_gridmap.columns - 1), clamp(current_position.y + offset_y, 0, enhanced_gridmap.rows - 1) ) # Check if the position is within movement range if not is_within_movement_range(random_position): attempts += 1 continue var cell_item = enhanced_gridmap.get_cell_item(Vector3i(random_position.x, 0, random_position.y)) if cell_item not in enhanced_gridmap.non_walkable_items and random_position != current_position: return random_position attempts += 1 return current_position func _physics_process(_delta): if is_multiplayer_authority(): rpc("remote_set_position", global_position) # Add this to your _process function if you don't have one func _process(delta): if is_multiplayer_authority(): if Input.is_action_just_pressed("grab_item"): # Define this input in project settings if grab_item(): rpc("display_message", "Item grabbed!") elif Input.is_action_just_pressed("put_item"): # Define this input in project settings if put_item(): rpc("display_message", "Item placed!") func _unhandled_input(event): var main = get_node("/root/Main") if not is_multiplayer_authority() or (main.turn_based_mode and (not is_my_turn or is_player_moving)): return if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: var camera = 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 = raycast_to_grid(from, to) if click_position != Vector2i(-1, -1): move_player_to_clicked_position(click_position) func raycast_to_grid(from: Vector3, to: Vector3) -> Vector2i: var plane = Plane(Vector3.UP, cell_offset.y) var intersection = plane.intersects_ray(from, to - from) if intersection: var adjusted_intersection = intersection - cell_offset var grid_position = Vector2i( floor(adjusted_intersection.x / cell_size.x), floor(adjusted_intersection.z / cell_size.z) ) if grid_position.x >= 0 and grid_position.x < enhanced_gridmap.columns and \ grid_position.y >= 0 and grid_position.y < enhanced_gridmap.rows: return grid_position return Vector2i(-1, -1) func is_within_movement_range(target_position: Vector2i) -> bool: var distance = 0 if use_diagonal_movement: # For diagonal movement, use max of x and y differences distance = max(abs(target_position.x - current_position.x), abs(target_position.y - current_position.y)) else: # For orthogonal movement, use Manhattan distance distance = abs(target_position.x - current_position.x) + \ abs(target_position.y - current_position.y) return distance <= movement_range #func move_player_to_clicked_position(grid_position: Vector2i): #if not is_multiplayer_authority(): #return # #if is_player_moving: #return # ## Check if the movement is within range #if not is_within_movement_range(grid_position): #print("Movement out of range") #return # #var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y)) # #if cell_item in enhanced_gridmap.non_walkable_items: #print("Cannot move to non-walkable cell") #return # #var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) # #if path.size() > 1: #path.pop_front() #rpc("start_movement_along_path", path) #else: #print("No valid path found") func move_player_to_clicked_position(grid_position: Vector2i): if not is_multiplayer_authority(): return if is_player_moving: return # Check if player has performed grab/put action if not has_performed_action and current_position != grid_position: rpc("display_message", "Must grab or place item before moving!") return if not is_within_movement_range(grid_position): print("Movement out of range") return var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y)) if cell_item in enhanced_gridmap.non_walkable_items: print("Cannot move to non-walkable cell") return rotate_towards_target(grid_position) var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position)) if path.size() > 1: path.pop_front() rpc("start_movement_along_path", path) else: print("No valid path found") @rpc("any_peer", "call_local") func start_movement_along_path(path: Array): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) tween.set_ease(Tween.EASE_IN_OUT) for point in path: var target_position = grid_to_world(Vector2i(point.x, point.y)) tween.tween_property(self, "position", target_position, 0.5) tween.tween_callback(func(): current_position = Vector2i(path[-1].x, path[-1].y) is_player_moving = false has_performed_action = false # Reset the action flag after movement enhanced_gridmap.clear_path_visualization() has_moved_this_turn = true var main = get_node("/root/Main") if main.turn_based_mode: end_turn() ) func move_bot_along_path(path: Array, bot_id: int): if not is_multiplayer_authority(): return rpc("start_bot_movement_along_path", path, bot_id) @rpc("any_peer", "call_local") func start_bot_movement_along_path(path: Array, bot_id: int): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) tween.set_ease(Tween.EASE_IN_OUT) for point in path: var target_position = grid_to_world(Vector2i(point.x, point.y)) tween.tween_property(self, "position", target_position, 0.5) tween.tween_callback(func(): current_position = Vector2i(path[-1].x, path[-1].y) is_player_moving = false enhanced_gridmap.clear_path_visualization() has_moved_this_turn = true var main = get_node("/root/Main") if main.turn_based_mode: end_turn() # Notify main that bot movement is complete if multiplayer.is_server(): main.bot_movement_completed(bot_id) ) func update_player_position(grid_position: Vector2i): position = grid_to_world(grid_position) func grid_to_world(grid_position: Vector2i) -> Vector3: var world_position = Vector3( grid_position.x * cell_size.x, cell_size.y, grid_position.y * cell_size.z ) world_position.x += cell_size.x * 0.5 world_position.z += cell_size.z * 0.5 if center_x: world_position.x += cell_size.x * 0.5 if center_y: world_position.y += cell_size.y * 0.5 if center_z: world_position.z += cell_size.z * 0.5 return world_position + cell_offset func start_turn(): has_moved_this_turn = false has_performed_action = false # Reset action flag at start of turn is_my_turn = true if is_multiplayer_authority(): rpc("display_message", "It's your turn!") func end_turn(): is_my_turn = false has_moved_this_turn = false if is_multiplayer_authority(): get_node("/root/Main").request_next_turn() @rpc("any_peer", "call_local", "unreliable") func remote_set_position(authority_position): global_position = authority_position @rpc("any_peer", "call_local") func display_message(message): $Bubble.show() $Bubble/Message.show() $Bubble/Message.text = str(message) await get_tree().create_timer(3).timeout $Bubble.hide() $Bubble/Message.hide() func initialize_random_goals(): goals.clear() var rng = RandomNumberGenerator.new() rng.randomize() for i in range(9): goals.append(rng.randi_range(7, 10)) if is_multiplayer_authority(): rpc("sync_goals", goals) func grab_item() -> bool: if not enhanced_gridmap: return false var current_cell = Vector3i(current_position.x, 1, current_position.y) var item = enhanced_gridmap.get_cell_item(current_cell) if item == -1: # No item to grab return false var empty_slot = playerboard.find(-1) if empty_slot == -1: # No empty slots return false playerboard[empty_slot] = item enhanced_gridmap.set_cell_item(current_cell, -1) if is_multiplayer_authority(): rpc("sync_playerboard", playerboard) has_performed_action = true # Set action flag return true func put_item() -> bool: if not enhanced_gridmap: return false var current_cell = Vector3i(current_position.x, 1, current_position.y) if enhanced_gridmap.get_cell_item(current_cell) != -1: return false # Cell is occupied var item_to_put = -1 var item_index = -1 for goal in goals: var index = playerboard.find(goal) if index != -1: item_to_put = goal item_index = index break if item_to_put == -1: return false enhanced_gridmap.set_cell_item(current_cell, item_to_put) playerboard[item_index] = -1 if is_multiplayer_authority(): rpc("sync_playerboard", playerboard) has_performed_action = true # Set action flag return true @rpc("any_peer", "call_local") func sync_goals(new_goals: Array): goals = new_goals @rpc("any_peer", "call_local") func sync_playerboard(new_playerboard: Array): playerboard = new_playerboard func rotate_towards_target(target_pos: Vector2i): var direction = Vector2( target_pos.x - current_position.x, target_pos.y - current_position.y ).normalized() target_rotation = atan2(direction.x, direction.y) # Create a tween for smooth rotation var tween = create_tween() tween.tween_property(self, "rotation:y", target_rotation, 0.2)