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()