diff --git a/addons/enhanced_gridmap/enhanced_gridmap.gd b/addons/enhanced_gridmap/enhanced_gridmap.gd index 7c220ec..0e79da1 100644 --- a/addons/enhanced_gridmap/enhanced_gridmap.gd +++ b/addons/enhanced_gridmap/enhanced_gridmap.gd @@ -353,7 +353,7 @@ func initialize_astar(): update_astar_costs() -func find_path(start: Vector2, end: Vector2, floor_index: int = 0) -> Array: +func find_path(start: Vector2, end: Vector2, floor_index: int = 0, clear_path_visual: bool = true) -> Array: var astar = astar_by_floor.get(floor_index) if not astar: return [] @@ -362,7 +362,9 @@ func find_path(start: Vector2, end: Vector2, floor_index: int = 0) -> Array: var end_point = end.y * columns + end.x path = astar.get_point_path(start_point, end_point) - clear_path_visualization(floor_index) + if clear_path_visual: + clear_path_visualization(floor_index) + set_cell_item(Vector3i(start.x, floor_index, start.y), start_item) set_cell_item(Vector3i(end.x, floor_index, end.y), end_item) for point in path: diff --git a/scenes/main.gd b/scenes/main.gd index f67cf05..637afa5 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -56,15 +56,6 @@ func _process(delta): if multiplayer.is_server() and game_started: if turn_based_mode: rpc("sync_turn_index", current_turn_index) - else: - pass - #bot_move_timer += delta - #if bot_move_timer >= BOT_MOVE_INTERVAL: - #bot_move_timer = 0.0 - #var current_bots = bots.duplicate() - #for bot_id in current_bots: - #if not moving_bots.get(bot_id, false): - #move_bot(bot_id) func setup_action_buttons(): move_button.pressed.connect(func(): set_action_state(ActionState.MOVING)) @@ -123,14 +114,17 @@ func set_action_state(new_state): return current_action_state = new_state - local_player_character.clear_highlights() - local_player_character.clear_playerboard_highlights() + if not local_player_character.is_bot: + local_player_character.clear_highlights() + local_player_character.clear_playerboard_highlights() match new_state: ActionState.MOVING: - local_player_character.highlight_movement_range() + if not local_player_character.is_bot: + local_player_character.highlight_movement_range() ActionState.GRABBING: - local_player_character.highlight_adjacent_cells() + if not local_player_character.is_bot: + local_player_character.highlight_adjacent_cells() if local_player_character.has_item_at_current_position(): local_player_character.highlighted_cells.append(local_player_character.current_position) local_player_character.enhanced_gridmap.set_cell_item( @@ -138,12 +132,15 @@ func set_action_state(new_state): local_player_character.enhanced_gridmap.hover_item ) ActionState.PUTTING: - local_player_character.highlight_occupied_playerboard_slots() + if not local_player_character.is_bot: + local_player_character.highlight_occupied_playerboard_slots() ActionState.RANDOMIZING: - local_player_character.highlight_random_valid_cells() + if not local_player_character.is_bot: + local_player_character.highlight_random_valid_cells() ActionState.ARRANGING: show_arrangement_ui() - local_player_character.highlight_occupied_playerboard_slots() + if not local_player_character.is_bot: + local_player_character.highlight_occupied_playerboard_slots() func update_button_states(): if not local_player_character or local_player_character.is_in_group("Bots"): @@ -166,8 +163,6 @@ func update_button_states(): randomize_button.disabled = local_player_character.has_performed_action arrange_button.disabled = not local_player_character.has_items_in_playerboard() - - func _on_playerboard_slot_clicked(event, slot_index): if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: if not local_player_character: @@ -273,9 +268,8 @@ func add_player_character(peer_id): update_playerboard_ui() func add_bot(bot_id): - if multiplayer.is_server(): - rpc("create_bot", bot_id) - #moving_bots[bot_id] = false + rpc("create_bot", bot_id) + @rpc("call_local") func create_bot(bot_id): @@ -376,8 +370,6 @@ func next_turn(): if multiplayer.is_server() and turn_based_mode: current_turn_index = (current_turn_index + 1) % players.size() rpc("set_current_turn", players[current_turn_index]) - #if players[current_turn_index] in bots: - #move_bot(players[current_turn_index]) func request_next_turn(): if multiplayer.is_server(): @@ -409,131 +401,3 @@ func end_current_turn(): if multiplayer.is_server(): next_turn() rpc("sync_turn_index", current_turn_index) - -#func move_bot(bot_id): - #if not multiplayer.is_server() or moving_bots.get(bot_id, false): - #return - # - #var bot = get_node_or_null(str(bot_id)) - #if not is_instance_valid(bot) or bot.is_player_moving: - #moving_bots.erase(bot_id) - #return - # - #if bot.action_points <= 0: - #if turn_based_mode: - #moving_bots[bot_id] = false - #end_current_turn() - #else: - #bot.action_points = 2 - #bot.has_moved_this_turn = false - #bot.has_performed_action = false - #moving_bots[bot_id] = false - #await get_tree().create_timer(0.5).timeout - #move_bot(bot_id) - #return - # - #moving_bots[bot_id] = true - #await get_tree().create_timer(0.5).timeout - # - #if not is_instance_valid(bot): - #moving_bots.erase(bot_id) - #return - # - #var best_move = evaluate_bot_move(bot) - #execute_bot_move(bot, bot_id, best_move) - -#func execute_bot_move(bot, bot_id, move): - #match move.action: - #"arrange": - #if bot.action_points >= 2: - #bot.arrange_playerboard_item(bot.find_best_arrangement_slot()) - #bot.action_points -= 2 - #moving_bots[bot_id] = false - #if bot.action_points > 0 or not turn_based_mode: - #move_bot(bot_id) - #elif turn_based_mode: - #end_current_turn() - # - #"grab", "put": - #var success = bot.grab_item(move.position) if move.action == "grab" else bot.put_item(move.position) - #if success: - #bot.action_points -= 1 - #moving_bots[bot_id] = false - #if bot.action_points > 0 or not turn_based_mode: - #move_bot(bot_id) - #elif turn_based_mode: - #end_current_turn() - # - #"move": - #if is_instance_valid(bot) and bot.action_points >= 1: - #var path = bot.enhanced_gridmap.find_path(Vector2(bot.current_position), Vector2(move.position)) - #if path.size() > 1: - #path.pop_front() - #var trimmed_path = path.slice(0, bot.movement_range) - #bot.rotate_towards_target(move.position) - #bot.move_bot_along_path(trimmed_path, bot_id) - #bot.action_points -= 1 - #else: - #moving_bots[bot_id] = false - #if bot.action_points > 0 or not turn_based_mode: - #move_bot(bot_id) - #elif turn_based_mode: - #end_current_turn() - #else: - #moving_bots[bot_id] = false - #if bot.action_points > 0 or not turn_based_mode: - #move_bot(bot_id) - #elif turn_based_mode: - #end_current_turn() - # - #_: - #moving_bots[bot_id] = false - #if turn_based_mode: - #end_current_turn() - #else: - #move_bot(bot_id) - -#func evaluate_bot_move(bot: Node) -> Dictionary: - #if not is_instance_valid(bot) or bot.action_points <= 0: - #return { "action": "none", "position": Vector2i.ZERO, "value": -1 } -# - #var moves = [] - # - #if bot.action_points >= 2 and bot.check_playerboard_arrangement(bot): - #moves.append({ "action": "arrange", "position": bot.current_position, "value": 20 }) -# - #if bot.action_points >= 1: - #var put_position = bot.find_best_put_position(bot) - #if put_position != Vector2i(-1, -1): - #moves.append({ "action": "put", "position": put_position, "value": 18 }) -# - #if bot.action_points >= 1 and not bot.playerboard_is_full(): - #var grab_position = bot.find_best_grab_position() - #if grab_position != Vector2i(-1, -1): - #moves.append({ "action": "grab", "position": grab_position, "value": 15 }) -# - #if bot.action_points >= 1 and not bot.has_moved_this_turn: - #var random_pos = bot.find_random_valid_position_in_range() - #if random_pos != bot.current_position: - #moves.append({ "action": "move", "position": random_pos, "value": 5 }) -# - #moves.sort_custom(func(a, b): return a.value > b.value) - #return moves[0] if moves.size() > 0 else { "action": "none", "position": bot.current_position, "value": 0 } - -#func bot_movement_completed(bot_id): - #if not multiplayer.is_server(): - #return - # - #moving_bots[bot_id] = false - #var bot = get_node_or_null(str(bot_id)) - # - #if not is_instance_valid(bot): - #moving_bots.erase(bot_id) - #return - # - #if bot.action_points > 0 or not turn_based_mode: - #await get_tree().create_timer(0.5).timeout - #if is_instance_valid(bot): - #move_bot(bot_id) - #else: - #end_current_turn() diff --git a/scenes/player.gd b/scenes/player.gd index ece9ff3..981d29a 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -57,35 +57,58 @@ func _ready(): # Initialize behavior tree for bots var behavior_tree = $BehaviorTree - - if is_in_group("Bots") and behavior_tree: - behavior_tree.enabled = true - behavior_tree.actor = self + # Early setup for bots + if is_bot or is_in_group("Bots"): + # Set Input process to false for bots immediately + set_process_input(false) + set_process_unhandled_input(false) + + # Disable visual highlights for bots + highlighted_cells.clear() + + if behavior_tree: + behavior_tree.enabled = is_multiplayer_authority() + behavior_tree.actor = self rpc("sync_bot_status", true) - # Rest of initialization + # Initialize bot-specific components + if enhanced_gridmap: + current_position = find_valid_starting_position() + update_player_position(current_position) + append_random_goals() + playerboard.resize(25) + playerboard.fill(-1) + return + + # Rest of initialization (only for human players) if enhanced_gridmap: 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(not is_in_group("Bots") and is_multiplayer_authority()) - append_random_goals() playerboard.resize(25) playerboard.fill(-1) + @rpc("any_peer", "call_local") func sync_bot_status(is_bot_status: bool): is_bot = is_bot_status if is_bot: - add_to_group("Bots", true) # Persistent group addition + add_to_group("Bots", true) + set_process_input(false) + set_process_unhandled_input(false) + + # Clear any existing highlights + highlighted_cells.clear() + #clear_highlights() + #clear_playerboard_highlights() + var behavior_tree = get_node_or_null("BehaviorTree") if behavior_tree: - behavior_tree.enabled = true + behavior_tree.enabled = is_multiplayer_authority() behavior_tree.actor = self if not is_multiplayer_authority(): behavior_tree.set_physics_process(false) @@ -96,8 +119,10 @@ func _physics_process(_delta): rpc("remote_set_position", global_position) func _unhandled_input(event): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots"): + set_process_unhandled_input(false) + set_process_input(false) + return # Use get_node_or_null for safer node access var main = get_tree().get_root().get_node_or_null("Main") @@ -108,6 +133,10 @@ func _unhandled_input(event): return if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + if is_bot or is_in_group("Bots"): + set_process_unhandled_input(false) + set_process_input(false) + return 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 @@ -137,6 +166,8 @@ func _on_slot_gui_input(event, slot_index, slot_ui) -> int: return -1 func handle_grid_click(grid_position: Vector2i): + if is_bot or is_in_group("Bots"): + return var main = get_tree().get_root().get_node_or_null("Main") if not main: push_error("Main node not found") @@ -252,15 +283,18 @@ func move_player_to_clicked_position(grid_position: Vector2i): break if valid_path: + path.pop_front() rpc("start_movement_along_path", path) action_points -= 1 - clear_highlights() + if not is_bot: + clear_highlights() + else: print("Path is blocked by other players") @rpc("any_peer", "call_local") -func start_movement_along_path(path: Array): +func start_movement_along_path(path: Array, clear_visual: bool = true): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) @@ -272,7 +306,10 @@ func start_movement_along_path(path: Array): tween.tween_callback(func(): current_position = Vector2i(path[-1].x, path[-1].y) is_player_moving = false - enhanced_gridmap.clear_path_visualization() + + if clear_visual: + enhanced_gridmap.clear_path_visualization() + has_moved_this_turn = path.size() <= movement_range var main = get_tree().get_root().get_node_or_null("Main") @@ -369,7 +406,7 @@ func grab_item(grid_position: Vector2i = current_position) -> bool: if item == -1: return false - if is_in_group("Bots"): + if is_in_group("Bots") or is_bot: var empty_slot = playerboard.find(-1) if empty_slot == -1: return false @@ -428,8 +465,9 @@ func put_item(grid_position: Vector2i = current_position) -> bool: has_performed_action = true consume_action_points(1) - clear_highlights() - clear_playerboard_highlights() + if not is_bot: + clear_highlights() + clear_playerboard_highlights() selected_playerboard_slot = -1 var main = get_tree().get_root().get_node_or_null("Main") @@ -442,9 +480,10 @@ func handle_put_action(): var main = get_tree().get_root().get_node_or_null("Main") if not main or action_points < 1: return - - clear_highlights() - clear_playerboard_highlights() + + if not is_bot: + clear_highlights() + clear_playerboard_highlights() # Highlight non-empty slots in playerboard for i in range(playerboard.size()): @@ -477,8 +516,9 @@ func handle_playerboard_slot_selected(slot_index: int): has_performed_action = true consume_action_points(1) - clear_highlights() - clear_playerboard_highlights() + if not is_bot: + clear_highlights() + clear_playerboard_highlights() selected_gridmap_position = Vector2i(-1, -1) main.set_action_state(main.ActionState.NONE) _after_action_completed() @@ -492,52 +532,9 @@ func handle_put_slot_selected(slot_index: int): if slot_index in highlighted_cells and playerboard[slot_index] in goals: selected_playerboard_slot = slot_index clear_highlights() - highlight_empty_adjacent_cells() + if not is_bot: + highlight_empty_adjacent_cells() -#func arrange_playerboard_item(slot_index: int): - #if action_points < 2 or playerboard[slot_index] == -1: - #return -# - #var selected_item = playerboard[slot_index] - #var adjacent_slots = get_adjacent_playerboard_slots(slot_index) -# - #var main = get_tree().get_root().get_node_or_null("Main") - #if not main or not main.playerboard_ui: - #return -# - #var selected_slot_ui = main.playerboard_ui.get_child(slot_index) - #if selected_slot_ui.get_child_count() > 1: - #selected_slot_ui.get_child(1).show() -# - #for adj_slot in adjacent_slots: - #if playerboard[adj_slot] == -1 or is_valid_arrangement_slot(slot_index, adj_slot): - #var adj_slot_ui = main.playerboard_ui.get_child(adj_slot) - #if adj_slot_ui.get_child_count() > 2: - #adj_slot_ui.get_child(2).show() -# - #main.update_playerboard_highlights(adjacent_slots) -# - #var target_slot = await _on_slot_gui_input(null, slot_index, selected_slot_ui) - # - #if selected_slot_ui.get_child_count() > 1: - #selected_slot_ui.get_child(1).hide() - # - #for adj_slot in adjacent_slots: - #var adj_slot_ui = main.playerboard_ui.get_child(adj_slot) - #if adj_slot_ui.get_child_count() > 2: - #adj_slot_ui.get_child(2).hide() -# - #if target_slot != -1 and (playerboard[target_slot] == -1 or is_valid_arrangement_slot(slot_index, target_slot)): - #var temp_item = playerboard[target_slot] - #playerboard[target_slot] = selected_item - #playerboard[slot_index] = temp_item -# - #if is_multiplayer_authority(): - #rpc("sync_playerboard", playerboard) - #consume_action_points(2) - #has_performed_action = true - #_after_action_completed() - #main.update_playerboard_ui() func arrange_playerboard_item(slot_index: int): if action_points < 2 or playerboard[slot_index] == -1: @@ -573,7 +570,7 @@ func arrange_playerboard_item(slot_index: int): slot.gui_input.connect(_on_slot_clicked.bind(i)) func _on_slot_clicked(event: InputEvent, slot_index: int): - if not event is InputEventMouseButton or not event.pressed or event.button_index != MOUSE_BUTTON_LEFT: + if not event is InputEventMouseButton or is_bot or not event.pressed or event.button_index != MOUSE_BUTTON_LEFT: return var main = get_tree().get_root().get_node_or_null("Main") @@ -596,8 +593,8 @@ func _on_slot_clicked(event: InputEvent, slot_index: int): has_performed_action = true # Clear highlights - clear_highlights() - clear_playerboard_highlights() + clear_highlights() + clear_playerboard_highlights() # Reset selection selected_playerboard_slot = -1 @@ -606,30 +603,6 @@ func _on_slot_clicked(event: InputEvent, slot_index: int): main.update_playerboard_ui() main.set_action_state(main.ActionState.NONE) - -#func check_playerboard_arrangement(bot: Node) -> bool: - #var goal_indices = [] # Store indices of non-empty goals - #var goal_items = [] # Store the actual goal items - # - ## Get all valid goals (non -1) - #for i in range(goals.size()): - #if goals[i] != -1: - #goal_indices.append(i) - #goal_items.append(goals[i]) - # - ## Check if current arrangement matches goals - #var current_items = [] - #for i in range(playerboard.size()): - #if playerboard[i] in goal_items: - #current_items.append(playerboard[i]) - # - ## Compare current order with goal order - #for i in range(min(current_items.size(), goal_items.size())): - #if current_items[i] != goal_items[i]: - #return true - # - #return false - func is_valid_arrangement_slot(from_slot: int, to_slot: int) -> bool: var from_row = from_slot / 5 var from_col = from_slot % 5 @@ -653,39 +626,6 @@ func get_adjacent_playerboard_slots(slot_index) -> Array: return adjacent -#func find_best_arrangement_slot() -> int: - #for i in range(playerboard.size()): - #if playerboard[i] != -1: - #var neighbors = get_adjacent_playerboard_slots(i) - #for adj_slot in neighbors: - #if playerboard[adj_slot] == -1 and playerboard[i] in goals: - #return adj_slot - #return playerboard.find(-1) - -#func find_best_put_position(bot: Node) -> Vector2i: - ## Find the first empty cell adjacent to a matching item in the playerboard - #for i in range(playerboard.size()): - #if playerboard[i] in goals: - #var neighbors = enhanced_gridmap.get_neighbors(current_position, 1) - #for neighbor in neighbors: - #var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y) - #if enhanced_gridmap.get_cell_item(cell) == -1: - #return neighbor.position - #return Vector2i(-1, -1) - -#func find_best_grab_position() -> Vector2i: - ## Find the first matching item in the grid or adjacent cells - #var current_cell = Vector3i(current_position.x, 1, current_position.y) - #if enhanced_gridmap.get_cell_item(current_cell) in goals: - #return current_position -# - #var neighbors = enhanced_gridmap.get_neighbors(current_position, 1) - #for neighbor in neighbors: - #var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y) - #if enhanced_gridmap.get_cell_item(cell) in goals: - #return neighbor.position -# - #return Vector2i(-1, -1) func has_item_at_current_position() -> bool: var current_cell = Vector3i(current_position.x, 1, current_position.y) @@ -698,8 +638,8 @@ func playerboard_is_full() -> bool: return playerboard.find(-1) == -1 func highlight_movement_range(): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return for x in range(enhanced_gridmap.columns): for z in range(enhanced_gridmap.rows): @@ -711,8 +651,8 @@ func highlight_movement_range(): enhanced_gridmap.set_cell_item(Vector3i(x, 0, z), enhanced_gridmap.hover_item) func highlight_adjacent_cells(): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return var current_cell = Vector3i(current_position.x, 1, current_position.y) if enhanced_gridmap.get_cell_item(current_cell) != -1: @@ -729,8 +669,8 @@ func highlight_adjacent_cells(): func highlight_empty_adjacent_cells(): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return # Clear previous highlights clear_highlights() @@ -754,8 +694,8 @@ func highlight_empty_adjacent_cells(): enhanced_gridmap.hover_item) func highlight_random_valid_cells(): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return var valid_cells = [] for x in range(enhanced_gridmap.columns): @@ -775,8 +715,8 @@ func highlight_random_valid_cells(): valid_cells.remove_at(index) func highlight_occupied_playerboard_slots(): - #if is_in_group("Bots"): - #return + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return var main = get_tree().get_root().get_node_or_null("Main") if not main or not main.playerboard_ui: @@ -800,6 +740,8 @@ func highlight_occupied_playerboard_slots(): main.update_playerboard_ui() func clear_highlights(): + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return if not enhanced_gridmap: return @@ -817,6 +759,8 @@ func clear_highlights(): child.hide() func clear_playerboard_highlights(): + if is_bot or is_in_group("Bots") or not is_multiplayer_authority(): + return var main = get_tree().get_root().get_node_or_null("Main") if main and main.playerboard_ui: for i in range(main.playerboard_ui.get_child_count()): diff --git a/scenes/player.tscn b/scenes/player.tscn index c242829..a75d7bd 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -104,7 +104,7 @@ script = ExtResource("20_24ja6") [node name="BehaviorTree" type="Node" parent="." node_paths=PackedStringArray("blackboard")] script = ExtResource("8_1o2fn") -tick_rate = 60 +tick_rate = 90 blackboard = NodePath("../Blackboard") [node name="Selector" type="Node" parent="BehaviorTree"] diff --git a/scripts/behaviors/actions/do_move.gd b/scripts/behaviors/actions/do_move.gd index ccfbc05..53aacfd 100644 --- a/scripts/behaviors/actions/do_move.gd +++ b/scripts/behaviors/actions/do_move.gd @@ -8,17 +8,22 @@ func tick(actor: Node, blackboard: Blackboard) -> int: if actor.action_points <= 0: return FAILURE - + + if not actor.is_bot and not actor.is_in_group("Bots"): + return FAILURE + # Execute movement if actor.is_within_movement_range(target_pos): - if actor.is_multiplayer_authority(): + if actor.is_bot: var path = actor.enhanced_gridmap.find_path( Vector2(actor.current_position), - Vector2(target_pos) + Vector2(target_pos), + 0, + false ) if path.size() > 1: path.pop_front() - actor.rpc("start_movement_along_path", path) + actor.rpc("start_movement_along_path", path, false) actor.action_points -= 1 blackboard.set_value("current_action", "moving") return SUCCESS diff --git a/scripts/bot_behavior.gd b/scripts/bot_behavior.gd index 2f6e1e6..813635b 100644 --- a/scripts/bot_behavior.gd +++ b/scripts/bot_behavior.gd @@ -1,5 +1,5 @@ extends BeehaveTree -# In bot_behavior.gd + func _ready(): if Engine.is_editor_hint(): return @@ -21,4 +21,4 @@ func _ready(): # Wait a frame to ensure all nodes are ready await get_tree().process_frame - enabled = true + enabled = parent.is_multiplayer_authority() and parent.is_bot