feat: bullrush branch - mekton bulls arena, HUD, NPC managers, godot_ai updates
This commit is contained in:
@@ -134,6 +134,56 @@ func _normalize_tile(tile: int) -> int:
|
||||
return tile - 4 # 11->7, 12->8, etc.
|
||||
return tile
|
||||
|
||||
# =============================================================================
|
||||
# Mekton Bulls mode helpers
|
||||
# =============================================================================
|
||||
|
||||
func is_mekton_bulls_mode() -> bool:
|
||||
return LobbyManager and LobbyManager.is_game_mode(GameMode.Mode.MEKTON_BULLS)
|
||||
|
||||
func _get_mekton_bulls_manager() -> Node:
|
||||
if gauntlet_manager_override and is_instance_valid(gauntlet_manager_override):
|
||||
return gauntlet_manager_override
|
||||
|
||||
var current = actor
|
||||
while current != null:
|
||||
var bm = current.get_node_or_null("MektonBullsManager")
|
||||
if bm: return bm
|
||||
current = current.get_parent()
|
||||
|
||||
var root = actor.get_tree().root
|
||||
var main = root.get_node_or_null("Main")
|
||||
if main:
|
||||
return main.get_node_or_null("MektonBullsManager")
|
||||
return null
|
||||
|
||||
func _get_active_bulls() -> Array:
|
||||
return actor.get_tree().get_nodes_in_group("MektonBulls")
|
||||
|
||||
func _is_cell_unsafe_in_mekton_bulls(pos: Vector2i) -> bool:
|
||||
"""Cell is unsafe if it's WATER, or if it's on the boundary (soon to be flooded)."""
|
||||
if not is_mekton_bulls_mode(): return false
|
||||
var bm = _get_mekton_bulls_manager()
|
||||
if not bm: return false
|
||||
|
||||
# Check if water
|
||||
var tile = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y))
|
||||
if tile == 24: # TILE_WATER
|
||||
return true
|
||||
|
||||
if bm.has_method("_is_boundary") and bm._is_boundary(pos):
|
||||
return true
|
||||
|
||||
# Bull proximity
|
||||
var bulls = _get_active_bulls()
|
||||
for b in bulls:
|
||||
var b_pos = enhanced_gridmap.local_to_map(b.position)
|
||||
# If cell is adjacent to the bull, it's unsafe.
|
||||
if abs(b_pos.x - pos.x) <= 1 and abs(b_pos.z - pos.y) <= 1:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
# =============================================================================
|
||||
# Goal Analysis
|
||||
# =============================================================================
|
||||
@@ -345,14 +395,28 @@ func find_best_tile_to_grab() -> Dictionary:
|
||||
|
||||
func find_nearest_tile_of_type(tile_types: Array) -> Vector2i:
|
||||
"""Find nearest tile matching any type in array using optimized spiral search."""
|
||||
var current_pos = actor.current_position
|
||||
|
||||
if not enhanced_gridmap:
|
||||
return Vector2i(-1, -1)
|
||||
|
||||
|
||||
if is_mekton_bulls_mode():
|
||||
# Return the nearest uncollected tile from our blueprint
|
||||
var bm = _get_mekton_bulls_manager()
|
||||
var pid = actor.get("peer_id") if "peer_id" in actor else actor.name.to_int()
|
||||
if bm and pid != null and bm.player_blueprints.has(pid):
|
||||
var bp = bm.player_blueprints[pid]
|
||||
var best_tile = Vector2i(-1, -1)
|
||||
var best_dist = INF
|
||||
for c in bp.cells:
|
||||
if enhanced_gridmap.get_cell_item(Vector3i(c.x, 0, c.y)) == bp.color:
|
||||
var dist = actor.current_position.distance_to(c)
|
||||
if dist < best_dist and _is_valid_move_target(c, true):
|
||||
best_dist = dist
|
||||
best_tile = c
|
||||
if best_tile != Vector2i(-1, -1):
|
||||
return best_tile
|
||||
|
||||
var current_pos = actor.current_position
|
||||
# Optimization: Start check at simple radius
|
||||
# If we find something in the spiral, it is guaranteed to be one of the nearest (by Chebyshev distance logic broadly, or just good enough)
|
||||
|
||||
var max_radius = 25 # Limit search range to prevent full map scans on huge maps
|
||||
if OS.has_feature("mobile"):
|
||||
max_radius = 15 # Stricter limit on mobile
|
||||
@@ -438,10 +502,43 @@ func find_nearest_roaming_tekton() -> Node3D:
|
||||
# Movement Strategy
|
||||
# =============================================================================
|
||||
|
||||
func _should_use_freeze() -> bool:
|
||||
if not is_mekton_bulls_mode(): return false
|
||||
var bm = _get_mekton_bulls_manager()
|
||||
if not bm: return false
|
||||
var pid = actor.get("peer_id") if "peer_id" in actor else actor.name.to_int()
|
||||
if not bm.player_powers.has(pid) or bm.player_powers[pid]["FREEZE"] <= 0: return false
|
||||
|
||||
var bulls = _get_active_bulls()
|
||||
var bot_pos = enhanced_gridmap.local_to_map(actor.position)
|
||||
for b in bulls:
|
||||
var b_pos = enhanced_gridmap.local_to_map(b.position)
|
||||
if abs(bot_pos.x - b_pos.x) <= 3 and abs(bot_pos.z - b_pos.y) <= 3:
|
||||
return true
|
||||
return false
|
||||
|
||||
func find_optimal_move_target() -> Vector2i:
|
||||
"""Calculate the best position to move towards."""
|
||||
"""Core decision logic. Evaluates sabotaging vs making progress."""
|
||||
var main = actor.get_tree().get_root().get_node_or_null("Main")
|
||||
var is_sng = LobbyManager.is_game_mode(GameMode.Mode.STOP_N_GO)
|
||||
if is_mekton_bulls_mode():
|
||||
# In Mekton Bulls, use powers if viable.
|
||||
if _should_use_freeze():
|
||||
var bm = _get_mekton_bulls_manager()
|
||||
var pid = actor.get("peer_id") if "peer_id" in actor else actor.name.to_int()
|
||||
bm.try_use_freeze.rpc_id(1) # Try emitting to server
|
||||
|
||||
# Knock another nearby player
|
||||
var mb_pid = actor.get("peer_id") if "peer_id" in actor else actor.name.to_int()
|
||||
var mb_bm = _get_mekton_bulls_manager()
|
||||
if mb_bm and mb_bm.player_powers.has(mb_pid) and mb_bm.player_powers[mb_pid]["KNOCK"] > 0:
|
||||
var opps = _get_opponents()
|
||||
for op in opps:
|
||||
var dist = actor.position.distance_to(op.position)
|
||||
if dist < enhanced_gridmap.cell_size.x * 2.0:
|
||||
mb_bm.try_use_knock.rpc_id(1, op.name.to_int(), actor.position.direction_to(op.position).normalized())
|
||||
break
|
||||
|
||||
var is_sng = LobbyManager and 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
|
||||
@@ -602,6 +699,11 @@ func _is_valid_move_target(pos: Vector2i, ignore_players: bool = false) -> bool:
|
||||
if not enhanced_gridmap or not enhanced_gridmap.is_position_valid(pos):
|
||||
return false
|
||||
|
||||
if is_mekton_bulls_mode():
|
||||
# Do not move into WATER or the boundary
|
||||
if _is_cell_unsafe_in_mekton_bulls(pos):
|
||||
return false
|
||||
|
||||
# Check Floor 0 (Ground/Walls)
|
||||
var floor_item = enhanced_gridmap.get_cell_item(Vector3i(pos.x, 0, pos.y))
|
||||
if floor_item == -1 or floor_item in enhanced_gridmap.non_walkable_items:
|
||||
|
||||
Reference in New Issue
Block a user