I need help with my enemy ai.

Godot Version

4.6.1

Hey people! I am currently working on my first game, but have problems with my state machine/ENEMY AI. It should patrol using waypoints as targets. The waypoints differ depending on the area the enemy is in. Also if an object or the player is in its vicinity, it should check for that object/the player. I know this code probably is a friggin mess. But I need to make it work somehow. I just do not know how…

extends CharacterBody3D
class_name ENEMY
const NAME = "TALLREAPER"
const SMOOTHING_FACTOR = 0.2
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var anim_playback = anim_tree.get("parameters/playback")
enum behavior {
sleep,
wait,
patrol,
check, 
chase,
camo,
expose,
hit,
dissolve
}
@export var executed_behavior: behavior
@export var WALK_SLOW_SPEED: float = 15.0  # Slower patrol speed
@export var WALK_FAST_SPEED: float = 30.0 # Fast chase speed (similar to player sprint)
@export var IDLE_SPEED: float = 0  
@export var CHASE_RANGE: float = 100.0     # Large detection range
@export var KILL_RANGE: float = 8.0    
@export var current_location = location.in_sanctum   # Close enough to attack
@onready var vision = $head/enemy_vision
@onready var player = %PLAYER
@onready var stones = get_tree().get_nodes_in_group("stone")
@export var stones_array: Array[RigidBody3D]
@onready var current_stone: Vector3
@onready var gems = get_tree().get_nodes_in_group("gem")
@export var gems_array: Array[RigidBody3D]
@onready var current_gem: Vector3
@onready var armor_stands = get_tree().get_nodes_in_group("armor_stand_spawners")
@onready var nav_agent: NavigationAgent3D = %NavigationAgent3D
@onready var nmy_lightning: GPUParticles3D = $nmy_lightning
@onready var lightning_timer: Timer = $nmy_lightning/lightning_timer


#var posibble_targets = Node3D.global_position
#waypoints
@onready var loc_check = $location_check
@export var atrium_waypoints: Array[Marker3D]
var atrium_wp_index: int = 1
@export var altar_waypoints: Array[Marker3D]
var altar_wp_index: int = 1
@export var storage_waypoints: Array[Marker3D]
var storage_wp_index: int = 1
@export var sanctum_waypoints: Array[Marker3D]
var sanctum_wp_index: int = 1
@export var forge_waypoints: Array[Marker3D]
var forge_wp_index: int = 1
@export var mines_waypoints: Array[Marker3D]
var mines_wp_index: int = 1
@export var cistern_waypoints: Array[Marker3D]
var cistern_wp_index: int = 1
@export var study_waypoints: Array[Marker3D]
var study_wp_index: int = 1
var checkpoints : Vector3
enum location {in_atrium, in_storage, in_cistern, in_altar, in_forge , in_mines, in_sanctum, in_study}
@export var waypoints : Array
@onready var atrium_area = $"../new_nav/ATRIUM"
@onready var forge_area = $"../new_nav/FORGE"
@onready var altar_area = $"../new_nav/ALTAR"
@onready var sanctum_area = $"../new_nav/SANCTUM"
@onready var study_area = $"../new_nav/STUDY"
@onready var storage_area = $"../new_nav/STORAGE"
@onready var cistern_area = $"../new_nav/CISTERN"
@onready var mines_area = $"../new_nav/MINES"
@onready var teleport_timer: Timer = $teleport_timer
@onready var shape_anim: AnimationPlayer = $dissolve_shape/shape_anim
@export var update_interval: float = 0.2
var last_player_pos: Vector3
var player_noticed = false
var knows_player_pos = false
#enemy player relationship
var player_is_crouching = false
var tally_on = false
var player_near = false
var rng = RandomNumberGenerator.new()
var noticed_smth = false
var is_chasing = false
#@onready var player_position = %PLAYER.get_global_position()

#var notice_likelihood = RandomNumberGenerator.new()
var current_waypoint_index: int = 1
# Simple state machine
#var current_state: ENEMY.State = ENEMY.State.IDLE
var current_behavior: ENEMY.behavior = behavior.wait
var patrol_target: Vector3
var storage_key = false 
var lock = false 
var marked_scare = false 
#var storage_loc = %storage_gate.get_global_position()
signal inform_base1
signal inform_base2
signal lock_player

#state signals 
signal investigate
signal hit 
signal dissolve 
signal camo 
signal expose 

var storage_open = false
var cistern_open = false
var forge_open = false
var mines_open = false
var study_open = false

var _gem_hits = 0
var vuln_state = false
var update_timer = 0.0
@onready var chase_music = $"../CEILING/chase_music"
func _ready():
	current_behavior = behavior.wait
	waypoints =[
	atrium_waypoints, 
	storage_waypoints, 
	forge_waypoints, 
	cistern_waypoints,
	altar_waypoints,
	sanctum_waypoints,
	altar_waypoints, 
	mines_waypoints
	]
	#print("waypoints count: ", waypoints.size())
func _physics_process(delta: float) -> void:
	print("player noticed", player_noticed)
	print("player near" , player_near)
	print(current_location)
	print(current_behavior)
	if lock==true:
		return
	if not player:
		return
	# ← ADD THIS HERE
	# Apply gravity - reduced for testing
	if not is_on_floor():
		velocity.y -= 10.0 * delta
		# Cap falling speed to prevent going through ground
		if velocity.y < -50.0:
			velocity.y = -50.0
	else:
		velocity.y = 0
	
	var distance_to_player = global_position.distance_to(player.global_position)
	# Reduced debug info (only print every 60 frames to reduce lag)
	# Simple state logic
	#update_state(distance_to_player)
	#execute_current_state(delta, distance_to_player)
	set_up_vision()
	#update_agent_target()
	move_towards_target() 
	print_current_behavior()
	move_and_slide()
	velocity.y = clamp(velocity.y, -0.5, 0.5)
func match_behavior():
	match current_behavior:
		behavior.sleep: sleep()
		behavior.patrol: patrol()
		behavior.wait: wait()
		#conditions for wait: nav agent patrol done, check done, player_lost
		behavior.check: check()
		behavior.chase: chase()
		behavior.hit: tr_hit()
		behavior.dissolve: tr_dissolve()
func wait():
	stop_moving()
	if $wait_timer.is_stopped():
		$wait_timer.start()
	update_agent_target()
	if player_near:
		change_behavior(behavior.check)
	elif player_noticed:
		change_behavior(behavior.chase)
	elif noticed_smth:
		change_behavior(behavior.check)
	elif _gem_hits == 2:
		change_behavior(behavior.dissolve)
	else: 
		await $wait_timer.timeout
func _on_wait_timer_timeout() -> void:
	print("wait timer fired, location: ", current_location, " forge wps: ", forge_waypoints.size())
	match current_location:
		location.in_atrium:
			if atrium_waypoints.is_empty(): return
			atrium_wp_index = (atrium_wp_index + 1) % atrium_waypoints.size()
			nav_agent.set_target_position(atrium_waypoints[atrium_wp_index].global_position)
		location.in_storage:
			if storage_waypoints.is_empty(): return
			storage_wp_index = (storage_wp_index + 1) % storage_waypoints.size()
			nav_agent.set_target_position(storage_waypoints[storage_wp_index].global_position)
		location.in_cistern:
			if cistern_waypoints.is_empty(): return
			cistern_wp_index = (cistern_wp_index + 1) % cistern_waypoints.size()
			nav_agent.set_target_position(cistern_waypoints[cistern_wp_index].global_position)
		location.in_altar:
			if altar_waypoints.is_empty(): return
			altar_wp_index = (altar_wp_index + 1) % altar_waypoints.size()
			nav_agent.set_target_position(altar_waypoints[altar_wp_index].global_position)
		location.in_forge:
			if forge_waypoints.is_empty(): return
			forge_wp_index = (forge_wp_index + 1) % forge_waypoints.size()
			nav_agent.set_target_position(forge_waypoints[forge_wp_index].global_position)
		location.in_mines:
			if mines_waypoints.is_empty(): return
			mines_wp_index = (mines_wp_index + 1) % mines_waypoints.size()
			nav_agent.set_target_position(mines_waypoints[mines_wp_index].global_position)
		location.in_sanctum:
			if sanctum_waypoints.is_empty(): return
			sanctum_wp_index = (sanctum_wp_index + 1) % sanctum_waypoints.size()
			nav_agent.set_target_position(sanctum_waypoints[sanctum_wp_index].global_position)
		location.in_study:
			if study_waypoints.is_empty(): return
			study_wp_index = (study_wp_index + 1) % study_waypoints.size()
			nav_agent.set_target_position(study_waypoints[study_wp_index].global_position)
	change_behavior(behavior.patrol)
func _on_atrium_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_atrium)
	else:
		return
func _on_storage_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_storage)
	else:
		return

func _on_forge_area_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_forge)
	else:
		return

func _on_cistern_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_cistern)
	else:
		return
func _on_mines_area_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_mines)
	else:
		return

func _on_sanctum_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_sanctum)
	else:
		return
func _on_altar_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_altar)
	else:
		return

func _on_study_body_entered(body: Node3D) -> void:
	if body.is_in_group("enemy_location"): 
		update_location(location.in_study)
	else:
		return
func update_location(new_location: ENEMY.location):
	if current_location == new_location:
		return
	current_location = new_location
	match current_location:
		location.in_atrium:  print("nmy in atr")
		location.in_cistern: print("nmy in cstr")
		location.in_storage: print("nmy in str")
		location.in_altar:   print("nmy in altr")
		location.in_forge:   print("nmy in frg")
		location.in_mines:   print("nmy in mns")
		location.in_sanctum: print("nmy in snct")
		location.in_study:   print("nmy in study")
	match current_behavior:
		behavior.patrol:
			pass
		behavior.check:
			pass
		behavior.chase:
			pass
######################################################################
func change_behavior(new_behavior: ENEMY.behavior):
	if current_behavior == new_behavior:
		return
	current_behavior = new_behavior
func print_current_behavior():
	match current_behavior:
		behavior.sleep:
			print(current_behavior, "nmy asleep")
		behavior.wait:
			print(current_behavior, "nmy waits")
		behavior.patrol:
			print(current_behavior, "nmy patrols")
		behavior.check:
			print(current_behavior, "nmy check")
		behavior.chase:
			print(current_behavior, "nmy chases")
func execute_behavior():
	pass
func sleep():
	is_chasing = false
func patrol():
	is_chasing = false

	#match current_location:
		#location.in_study:
			#nav_agent.set_target_position(study_waypoints[study_wp_index].global_position)
		#location.in_altar:
			#nav_agent.set_target_position(altar_waypoints[altar_wp_index].global_position)
		#location.in_sanctum:
			#nav_agent.set_target_position(sanctum_waypoints[sanctum_wp_index].global_position)
		#location.in_mines:
			#nav_agent.set_target_position(mines_waypoints[mines_wp_index].global_position)
		#location.in_cistern:
			#nav_agent.set_target_position(cistern_waypoints[cistern_wp_index].global_position)
		#location.in_forge:
			#nav_agent.set_target_position(forge_waypoints[forge_wp_index].global_position)
		#location.in_storage:
			#nav_agent.set_target_position(storage_waypoints[storage_wp_index].global_position)
		#location.in_atrium:
			#nav_agent.set_target_position(atrium_waypoints[atrium_wp_index].global_position)
			#print(nav_agent.get_target_position())
	#anim_playback.travel("walk_slo")
	var next_path_position = nav_agent.get_next_path_position()
	var direction = global_position.direction_to(nav_agent.get_target_position())
	$nav_timer.start()

	if direction.length() > 0.1:
		var target_angle = atan2(direction.x, direction.z)
		rotation.y = lerp_angle(
			rotation.y,
			target_angle,
			5.0 * get_physics_process_delta_time()
		)
	if nav_agent.is_navigation_finished():
		change_behavior(behavior.wait)
	elif player_near:
		change_behavior(behavior.check)
	elif noticed_smth:
		change_behavior(behavior.check)
	elif player_noticed: 
		change_behavior(behavior.chase)
	elif nav_agent.is_navigation_finished():
		change_behavior(behavior.wait)
	elif _gem_hits ==2:
		change_behavior(behavior.dissolve)
	else: 
		return
	update_agent_target()
	print("patrolling now")
	print("ptrol")


func check():
	is_chasing = false
	nav_agent.set_target_position(checkpoints)
	if player_noticed: 
		change_behavior(behavior.chase)
	elif nav_agent.is_navigation_finished():
		change_behavior(behavior.wait)
	elif _gem_hits ==2:
		change_behavior(behavior.dissolve)
	elif nav_agent.is_navigation_finished():
		change_behavior(behavior.wait)
	else:
		return
	anim_playback.travel("walk_slo")
func chase():
	player_near = true
	is_chasing = true
	nav_agent.set_target_position(%PLAYER.global_position)
	anim_playback.travel("walk_fast")
	var direction = global_position.direction_to(%PLAYER.global_position)
	look_at_from_position(global_position, %PLAYER.global_position)
	rotate_y(PI)
	if nav_agent.is_navigation_finished():
		change_behavior(behavior.wait)
	elif _gem_hits ==2:
		change_behavior(behavior.dissolve)
	elif !player_noticed and player_near:
		change_behavior(behavior.check)
	elif !player_noticed and !player_near:
		change_behavior(behavior.wait)
func tr_hit():
	stop_moving()
	emit_signal("hit")
	anim_playback.travel("hit")
	if anim_playback.anmiation_finished("hit"):
		if player_noticed:
			change_behavior(behavior.chase)
		else:
			change_behavior(behavior.wait)
	elif anim_playback.get_current_node() != "hit":
		if player_noticed:
			change_behavior(behavior.chase)
		else:
			change_behavior(behavior.wait)
	exit_hit()
func exit_hit():
	if player_near:
		change_behavior(behavior.check)
	elif noticed_smth:
		change_behavior(behavior.check)
	elif player_noticed: 
		change_behavior(behavior.chase)
	elif _gem_hits ==2:
		change_behavior(behavior.dissolve)
	else:
		change_behavior(behavior.wait)
func tr_dissolve():
	$dissolve_shape.show()
	$dissolve_shape/dissolve_shape2.show()
	nav_agent.set_target_position(self.global_position)
	velocity = 0*self.global_position
	anim_playback.travel("idle")
	shape_anim.play("shape_down")
	if shape_anim.is_animation_active() == false:
		teleport()
func teleport():
	var spawn_points = get_tree().get_nodes_in_group("enemy_spawner")
	print("found spawn points: ", spawn_points.size())
	
	if spawn_points.size() > 0:
		process_mode = Node.PROCESS_MODE_DISABLED
		
		await get_tree().create_timer(5.0).timeout
		
		var random_spawn = spawn_points[randi() % spawn_points.size()]
		
		# Move far away to clear collisions
		global_position = Vector3(0, -9999, 0)
		await get_tree().create_timer(0.1).timeout
		
		# Now move to spawn point
		global_position = random_spawn.global_position + Vector3(0, 30, 0)
		process_mode = Node.PROCESS_MODE_INHERIT
		
		# Reset dissolve shapes for next cycle
		$dissolve_shape.hide()
		$dissolve_shape/dissolve_shape2.hide()
		print("enemy respawned at: ", global_position)
func player_lost():
	player_near = false
	player_noticed = false 
	is_chasing = false
#func _on_player_noticed_timeout() -> void:
	#change_behavior(behavior.chase)
	#update_agent_target()


#func move_toward_target(target: Vector3, speed: float, delta: float):
	#var direction = (target - global_position)
	#direction.y = 0  # Only move horizontally
func kill_player():
	print("TALLREAPER: KILL ATTEMPT!")
	
	# Add your kill logic here
	if player.has_method("die"):
		player.die()



func set_up_vision():
	pass
func _on_player_player_crouches() -> void:
	player_is_crouching = true


func _on_player_player_stands() -> void:
	player_is_crouching = false
	
func _on_perception_enemy_body_entered(body: Node3D) -> void:
	if body.is_in_group("stone"):
		var stone_notice_likelihood = rng.randf_range(30, 100)
		print(stone_notice_likelihood)
		if stone_notice_likelihood > 50:
			noticed_smth = true
			current_stone = body.global_position
			checkpoints = current_stone
		else:
			noticed_smth = false
	elif body.is_in_group("gem"):
		var stone_notice_likelihood = rng.randf_range(30, 100)
		print(stone_notice_likelihood)
		if stone_notice_likelihood > 50:
			noticed_smth = true
			current_gem = body.global_position
			checkpoints = current_gem
		else:
			noticed_smth = false
	elif body.is_in_group("player")and player_is_crouching == true:
		player_near = true
		if tally_on:
			var player_notice_likelihood = rng.randf_range(40, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		elif !tally_on:
			var player_notice_likelihood = rng.randf_range(15, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
	elif body.is_in_group("player") and player_is_crouching == false:
		player_near = true
		if tally_on:
			var player_notice_likelihood = rng.randf_range(40, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		elif !tally_on: 
			var player_notice_likelihood = rng.randf_range(35, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		else:
			noticed_smth = false
			player_noticed = false
	update_agent_target()
func play_chase_mus():
	if player_noticed: 
		chase_music.play()
	else:
		chase_music.stop()

	#if marked_scare == true:
		#emit_signal("inform_base1")
		#lock = true
		##behavior.curse
		#emit_signal("lock_player")
		#$scare_duration.start()
func _on_player_obtained_st_key() -> void:
	storage_key = true 
func _on_wake_area_body_entered(body: Node3D) -> void:
	if body.is_in_group("player") and storage_key == true :
		global_position = $"../CORRIDOR/enemy_instantiator".global_position
		lock = true
		$"../PLAYER/head/interaction_manager/tomb_curse_audio/show_screen".start()
		emit_signal("lock_player")
	else:
		return

signal unlock_player
func _on_tomb_curse_audio_finished() -> void:
	lock = false
	player_noticed = true
	$marked_function_enabler_timer.start()
	emit_signal("unlock_player")

func _on_marked_function_enabler_timer_timeout() -> void:
	marked_scare = true 
	print("lol")

func _on_scare_duration_timeout() -> void:
	get_tree().paused = false
	emit_signal("inform_base2")

func _on_perception_enemy_body_exited(body: Node3D) -> void:
	if body.is_in_group("player"):
		$body_ext_timer.start()
		await $body_ext_timer.timeout
		player_near=false
func _on_body_ext_timer_timeout() -> void:
	if not player_near: 
		player_near = false


func _on_chase_check_cooldown_timeout() -> void:
	if not player_near and not player_noticed:
		player_lost()


func _on_hurtbox_body_entered(body: Node3D) -> void:
	if body.is_in_group("gem"):
		_gem_hits +=1
		$nmy_lightning.show()
		$nmy_lightning/lightning_timer.start()
		$nmy_lightning/impact.play()
		await $nmy_lightning/lightning_timer.timeout
		$nmy_lightning.hide()
		print("gem_hits", _gem_hits)
		if _gem_hits == 2:
			print("gem_hits", _gem_hits)
			change_behavior(behavior.dissolve)
		else:
			change_behavior(behavior.hit)
	elif body.is_in_group("stone"):
		change_behavior(behavior.hit)

func _on_hit_timer_timeout() -> void:
	if player_noticed == true:
		change_behavior(behavior.chase)
	if player_noticed == false:
		change_behavior(behavior.check)


func _on_nav_timer_timeout() -> void:
	pass
	#nav_agent.set_target_position(waypoints[current_waypoint_index +1].global_position)
func get_waypoint_name() -> String:
	#if waypoints.is_empty():
		#return "No Waypoints"
	#if current_waypoint_index >= waypoints.size():
		#current_waypoint_index = 0
	#return waypoints[current_waypoint_index].name
#########################################################
	if altar_waypoints.is_empty():
		return "No altar Waypoints"

	if altar_wp_index >= altar_waypoints.size():
		altar_wp_index = 0
	return altar_waypoints[altar_wp_index].name
#########################################################
	if atrium_waypoints.is_empty():
		return "No atr Waypoints"

	if atrium_wp_index >= atrium_waypoints.size():
		atrium_wp_index = 0
	return atrium_waypoints[atrium_wp_index].name
#########################################################
	if storage_waypoints.is_empty():
		return "No str Waypoints"

	if storage_wp_index >= storage_waypoints.size():
		storage_wp_index = 0
	return storage_waypoints[storage_wp_index].name
#########################################################
	if forge_waypoints.is_empty():
		return "No forge Waypoints"

	if forge_wp_index >= forge_waypoints.size():
		forge_wp_index = 0
	return forge_waypoints[forge_wp_index].name
#########################################################
	if mines_waypoints.is_empty():
		return "No mines Waypoints"

	if mines_wp_index >= mines_waypoints.size():
		mines_wp_index = 0
	return mines_waypoints[mines_wp_index].name
#########################################################
	if cistern_waypoints.is_empty():
		return "No mines Waypoints"

	if cistern_wp_index >= cistern_waypoints.size():
		cistern_wp_index = 0
	return cistern_waypoints[cistern_wp_index].name
#########################################################
	if sanctum_waypoints.is_empty():
		return "No sanctum Waypoints"

	if sanctum_wp_index >= sanctum_waypoints.size():
		sanctum_wp_index = 0
	return sanctum_waypoints[sanctum_wp_index].name
#########################################################
	if study_waypoints.is_empty():
		return "No sanctum Waypoints"

	if study_wp_index >= study_waypoints.size():
		study_wp_index = 0
	return sanctum_waypoints[sanctum_wp_index].name
func move_towards_target():
	if nav_agent.is_navigation_finished():
		return
	if not nav_agent.is_target_reachable():
		return
	var next_pos = nav_agent.get_next_path_position()
	var direction = global_position.direction_to(next_pos)
	direction.y = 0
	if direction.length() < 0.1:
		return
	match current_behavior:
		behavior.patrol, behavior.check:
			velocity.x = direction.x * WALK_SLOW_SPEED
			velocity.z = direction.z * WALK_SLOW_SPEED
		behavior.chase:
			velocity.x = direction.x * WALK_FAST_SPEED
			velocity.z = direction.z * WALK_FAST_SPEED
	var target_angle = atan2(direction.x, direction.z)
	rotation.y = lerp_angle(rotation.y, target_angle, 5.0 * get_physics_process_delta_time())



func _on_show_screen_timeout() -> void:
	emit_signal("inform_base1")

func _on_navigation_agent_3d_velocity_computed(safe_velocity: Vector3) -> void:
	pass # Replace with function body.


func _on_tally_light_visibility_changed() -> void:
	if $"../PLAYER/newplayer_ver69/MAIN/Skeleton3D/BoneAttachment3D/tally/Cone/tally_light".visible:
		tally_on = true
		print("tr knows its lit")
	else:
		tally_on = false
		print("tr knows it was lit")


func _on_player_ping_position() -> void:
	last_player_pos = player.global_position

func _on_atrium_location_atrium() -> void:
	update_location(location.in_atrium)

func _on_altar_location_altar() -> void:
	update_location(location.in_altar)

func _on_cistern_location_cistern() -> void:
	update_location(location.in_cistern)

func _on_storage_location_storage() -> void:
	update_location(location.in_storage)

func _on_sanctum_location_sanctum() -> void:
	update_location(location.in_sanctum)

func _on_study_location_study() -> void:
	update_location(location.in_study)

func _on_mines_area_location_mines() -> void:
	update_location(location.in_mines)


func _on_forge_area_location_forge() -> void:
	update_location(location.in_forge)

func _on_player_open_cistern() -> void:
	cistern_open = true

func _on_player_open_forge() -> void:
	forge_open = true


func _on_player_open_mines() -> void:
	mines_open = true


func _on_player_open_storage() -> void:
	storage_open = true
#func player_found():
		#change_behavior(behavior.chase)
		#current_behavior = behavior.chase
		#update_agent_target()


func _on_search_player_timer_timeout() -> void:
	#change_behavior(behavior.wait)
	pass
#func move_towards(next_pos: Vector3, speed: float) -> void:
	#var dir =(next_pos - global_transform.origin)
	#dir.y = 0
	#if is_zero_approx( dir.lenght()):
		#velocity.x = lerp(velocity.x, 0.0, SMOOTHING_FACTOR)
		#velocity.z = lerp(velocity.z, 0.0, SMOOTHING_FACTOR)
		#return
#
	#dir = dir.normalized()
	#var current_facing = global_transform.basis.z
	#var new_dir = current_facing.slerp(dir, SMOOTHING_FACTOR).normalized()
	#look_at(global_transform.origin + new_dir, Vector3.UP)
	

	#match current_behavior:
		#behavior.patrol:
			#velocity.x = dir.x * WALK_SLOW_SPEED
			#velocity.z = dir.z * WALK_SLOW_SPEED
			#match current_location:
				#location.in_atrium:
					#next_pos = atrium_waypoints[atrium_wp_index].global_position
				#location.in_storage:
					#next_pos = storage_waypoints[storage_wp_index].global_position
				#location.in_cistern:
					#next_pos = cistern_waypoints[cistern_wp_index].global_position
				#location.in_mines:
					#next_pos = mines_waypoints[mines_wp_index].global_position
				#location.in_altar:
					#next_pos = altar_waypoints[altar_wp_index].global_position
				#location.in_forge:
					#next_pos = forge_waypoints[forge_wp_index].global_position
				#location.in_sanctum:
					#next_pos = sanctum_waypoints[sanctum_wp_index].global_position
		#behavior.check:
			#pass
		#behavior.chase:
			#velocity.x = dir.x * WALK_FAST_SPEED
			#velocity.z = dir.z * WALK_FAST_SPEED
			#next_pos = player.global_position

func _update_path(delta):
	update_timer -= delta
	if update_timer <= 0.0:
		#execute_behavior()
		update_timer = update_interval
func update_agent_target():
	match current_behavior: 
		behavior.patrol:
			match current_location:
				location.in_study:
					nav_agent.set_target_position(study_waypoints[study_wp_index].global_position)
				location.in_altar:
					nav_agent.set_target_position(altar_waypoints[altar_wp_index].global_position)
				location.in_sanctum:
					nav_agent.set_target_position(sanctum_waypoints[sanctum_wp_index].global_position)
				location.in_mines:
					nav_agent.set_target_position(mines_waypoints[mines_wp_index].global_position)
				location.in_cistern:
					nav_agent.set_target_position(cistern_waypoints[cistern_wp_index].global_position)
				location.in_forge:
					nav_agent.set_target_position(forge_waypoints[forge_wp_index].global_position)
				location.in_storage:
					nav_agent.set_target_position(storage_waypoints[storage_wp_index].global_position)
				location.in_atrium:
					nav_agent.set_target_position(atrium_waypoints[atrium_wp_index].global_position)
					print(nav_agent.get_target_position())
		behavior.chase:
			nav_agent.set_target_position(player.global_transform.origin)
		behavior.check:
			nav_agent.set_target_position(checkpoints)


func _on_shape_anim_animation_finished(shape_down) -> void:
	self.queue_free()
	teleport()


func _on_perception_enemy_player_near() -> void:
	player_near=true


func _on_perception_enemy_player_noticed() -> void:
	if player_is_crouching == true:
		player_near = true
		if tally_on:
			var player_notice_likelihood = rng.randf_range(40, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		elif !tally_on:
			var player_notice_likelihood = rng.randf_range(15, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
	elif player_is_crouching == false:
		player_near = true
		if tally_on:
			var player_notice_likelihood = rng.randf_range(40, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		elif !tally_on: 
			var player_notice_likelihood = rng.randf_range(35, 100)
			print("tr noticed" , player_notice_likelihood)
			if player_notice_likelihood > 50:
				player_noticed = true
			elif player_notice_likelihood < 50:
				player_noticed = false
		else:
			noticed_smth = false
			player_lost()
func close_gates():
	pass


func _on_navigation_agent_3d_navigation_finished() -> void:
	print("nmy reached target", current_behavior)
func if_player_near():
	if player_near:
		change_behavior(behavior.check)
		nav_agent.update_path_position(player.global_position)
func if_player_noticed():
	if player_noticed:
		change_behavior(behavior.chase)
		nav_agent.update_path_position(player.global_position)
func stop_moving():
	velocity = IDLE_SPEED*velocity
	_on_hit_timer_timeout()


func _on_vision_1_player_seen() -> void:
	player_noticed = true


func _on_vision_4_player_seen() -> void:
	player_noticed = true


func _on_vision_5_player_seen() -> void:
	player_noticed = true


func _on_vision_2_player_seen() -> void:
	player_noticed = true


func _on_vision_7_player_seen() -> void:
	player_noticed = true


func _on_vision_3_player_seen() -> void:
	player_noticed = true


func _on_vision_6_player_seen() -> void:
	player_noticed = true


func _on_notice_area_body_entered(body: Player) -> void:
	player_noticed = true 


func _on_notice_area_body_exited(body: Player) -> void:
	$chase_check_cooldown.start()
#
#
#func _on_vision_1_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_4_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_5_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_2_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_7_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_3_player_lost() -> void:
	#$chase_check_cooldown.start()
#
#
#func _on_vision_6_player_lost() -> void:
	#$chase_check_cooldown.start()

What do you expect to happen versus what really happens? Where do you think the problem(s) lies within this huge script? Can you narrow down what you want us to help with and what you’ve tracked down already?

So the enemy doesnt switch states. moreover it does not recognize the waypoints that are corresponding to the areas/locations, it doesnt move at all…

Setup some print statements between and inside of these functions. Check your velocity after each step.

1 Like