Files
wretched/entities/npc_backup.gd
2025-08-12 04:49:06 -04:00

243 lines
7.5 KiB
GDScript

extends CharacterBody3D
var walk_speed : float = 2.0
var run_speed : float = 5.0
@export var waypoint_route : Node3D
var state_change_cooldown : float = 0.1
var alert_escalation_time : float = 3.0
var suspicion_decay_time : float = 1.0
@export var behavior_type : String = "frozen"
var state : String = "patrol"
var current_waypoint : int = 0
var paused : bool = false
var turntoward : float = 0.0
var lastseenpos : Vector3
var pathupdateinterval : float = 0.75
@export var appearance : String = "guard"
var current_path: PackedVector3Array
@onready var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
var current_path_index: int = 0
var current_path_point: Vector3
@onready var overheadstatus : Control = $StatusSprite/SubViewport/OverheadStatus
func _ready() -> void:
overheadstatus.set_nothing()
overheadstatus.set_timer(-1)
if appearance == "guard":
$CharacterArmature/Skeleton3D/head_guard.visible = true
$CharacterArmature/Skeleton3D/body_guard.visible = true
$CharacterArmature/Skeleton3D/feet_guard.visible = true
$CharacterArmature/Skeleton3D/legs_guard.visible = true
elif appearance == "barista":
$CharacterArmature/Skeleton3D/head_barista.visible = true
$CharacterArmature/Skeleton3D/body_barista.visible = true
$CharacterArmature/Skeleton3D/feet_barista.visible = true
$CharacterArmature/Skeleton3D/legs_barista.visible = true
func _physics_process(delta: float) -> void:
if behavior_type == "frozen":
sight_test()
elif behavior_type == "guard":
process_alerts()
if not is_on_floor():
velocity += get_gravity() * delta
if !current_path.is_empty() and behavior_type == "guard" and (state == "patrol" or state == "pursue_walkto"):
current_path_point = current_path[current_path_index]
walk_toward(current_path_point)
if global_transform.origin.distance_to(current_path_point) <= 0.6:
current_path_index += 1
if current_path_index >= current_path.size():
clearpath()
if state == "patrol":
var wayedpoint = waypoint_route.get_children()[current_waypoint]
if wayedpoint.pausetime > 0:
paused = true
$WaypointPauseTimer.start(wayedpoint.pausetime)
$AnimationPlayer.play(wayedpoint.animation)
if wayedpoint.turntoward == true:
turntoward = wayedpoint.global_rotation.y
else:
turntoward = $CharacterArmature.global_rotation.y
current_waypoint += 1
if current_waypoint > waypoint_route.get_child_count()-1:
current_waypoint = 0
if state == "pursue_walkto":
print("done!")
state = "suspicion_start"
$StateChangeTimer.start(state_change_cooldown)
print("player sighted! state changed to suspicion_start")
overheadstatus.set_3dots()
overheadstatus.set_timer(-1)
else:
stand_still()
if paused and state == "patrol":
# overheadstatus.set_timer(100-(($WaypointPauseTimer.time_left / $WaypointPauseTimer.wait_time)*100))
if $CharacterArmature.global_rotation.y != turntoward:
lerp_toward(turntoward)
move_and_slide()
animate()
func animate():
if velocity.length() > 0:
$AnimationPlayer.play("Walk")
elif !paused:
$AnimationPlayer.play("Idle_Neutral")
func walk_toward(point: Vector3):
var direction = global_transform.origin.direction_to(point)
velocity.x = direction.x * walk_speed
velocity.z = direction.z * walk_speed
lerp_toward(atan2(velocity.x, velocity.z))
func stand_still():
velocity.x = 0
velocity.z = 0
func sight_test():
var seeingplayer : bool
seeingplayer = checksight()
if seeingplayer:
overheadstatus.set_exclamationmark()
else:
overheadstatus.set_nothing()
func process_alerts():
var seeingplayer : bool
if state == "patrol":
seeingplayer = checksight()
if seeingplayer:
state = "suspicion_start"
$StateChangeTimer.start(state_change_cooldown)
print("player sighted! state changed to suspicion_start")
return
if state == "suspicion":
seeingplayer = checksight()
if !seeingplayer and $StateChangeTimer.is_stopped():
$StateChangeTimer.start(suspicion_decay_time)
elif seeingplayer:
if !$StateChangeTimer.is_stopped(): $StateChangeTimer.stop()
overheadstatus.set_questionmark()
var percent : float = 100 - (($AlertEscalationTimer.time_left / alert_escalation_time) * 100)
overheadstatus.set_timer(percent)
if velocity.length() == 0: lerp_toward(turntoward)
if state == "pursue_walkto":
seeingplayer = checksight()
if seeingplayer:
print("update path?")
if !current_path.is_empty() and (current_path[current_path.size()-1].distance_to(lastseenpos) > 1):
setpath(lastseenpos)
print("updated path!")
func nextwaypoint():
var waypoint = waypoint_route.get_children()[current_waypoint]
var target_position: Vector3 = waypoint.global_transform.origin
setpath(target_position)
func setpath(target_position):
clearpath()
var start_position: Vector3 = global_transform.origin
current_path = NavigationServer3D.map_get_path(
default_3d_map_rid,
start_position,
target_position,
true
)
func clearpath():
current_path = []
current_path_index = 0
current_path_point = global_transform.origin
velocity.x = 0
velocity.z = 0
func checksight():
var seenthings = $CharacterArmature/SightCollider.get_overlapping_bodies()
if !seenthings.is_empty():
for item in seenthings:
if item.get_name() == "PlayerVisibilityShape":
if sightraycheck(item) == true:
return true
return false
func sightraycheck(target):
var radius = target.shape_owner_get_shape(0,0).radius
var height : float
var tramsorm : Transform3D
if target.get_parent().get_parent().crouched:
height = target.shape_owner_get_shape(1,0).height
tramsorm = target.shape_owner_get_transform(1).rotated(Vector3(0,1,0),target.global_rotation.y)
else:
height = target.shape_owner_get_shape(0,0).height
tramsorm = target.shape_owner_get_transform(0).rotated(Vector3(0,1,0),target.global_rotation.y)
var top = to_local(target.global_transform.origin - $CharacterArmature/SightCollider/SightRay.transform.origin + tramsorm.origin + Vector3(0, (height/2)-0.1, 0))
$CharacterArmature/SightCollider/SightRay.target_position = top
# $CharacterArmature/SightCollider/SightRay.global_rotation = Vector3(0,0,0)
$CharacterArmature/SightCollider/SightRay.force_raycast_update()
if $CharacterArmature/SightCollider/SightRay.is_colliding():
if $CharacterArmature/SightCollider/SightRay.get_collider().get_name() == "PlayerVisibilityShape":
turntoward = (Vector2(target.global_transform.origin.z, target.global_transform.origin.x) - Vector2($CharacterArmature.global_transform.origin.z, $CharacterArmature.global_transform.origin.x)).angle()
lastseenpos = target.global_transform.origin
return true
return false
func lerp_toward(angle: float):
$CharacterArmature.global_rotation.y = lerp_angle($CharacterArmature.global_rotation.y, angle, 0.15)
func _on_state_change_timer_timeout() -> void:
$StateChangeTimer.stop()
$AlertEscalationTimer.stop()
if state == "suspicion_start":
state = "suspicion"
$AlertEscalationTimer.start(alert_escalation_time)
return
if state == "suspicion":
state = "patrol"
overheadstatus.set_3dots()
overheadstatus.set_timer(-1)
return
if state == "pursue_start":
setpath(lastseenpos)
state = "pursue_walkto"
return
func _on_alert_escalation_timer_timeout() -> void:
$AlertEscalationTimer.stop()
if state == "suspicion":
state = "pursue_start"
$StateChangeTimer.start(state_change_cooldown)
overheadstatus.set_timer(-1)
overheadstatus.set_exclamationmark()
func _on_waypoint_pause_timer_timeout() -> void:
$WaypointPauseTimer.stop()
if paused:
paused = false