8462a2fde7
- Added SymptomManager autoload for managing symptom intensities. - Introduced nausea tilt effect for camera roll based on nausea intensity. - Created color desaturation shader and overlay for visual feedback. - Developed TreatmentManager to handle nausea ramping during IV treatment. - Added hospital room scene with first-person controller and interactions. - Implemented sit-down interaction for the treatment chair. - Created IV insertion sequence with animations and completion signal. - Added player controller with movement and interaction capabilities. - Integrated nausea effects into the player experience with smooth transitions.
106 lines
2.8 KiB
GDScript
106 lines
2.8 KiB
GDScript
class_name ChairInteraction
|
|
extends Area3D
|
|
## Sit-down interaction for the treatment chair.
|
|
## Shows a prompt when the player is in range, sits them on `interact`,
|
|
## smoothly lerps the camera to a seated pose, locks movement, and emits
|
|
## `player_seated`. Standing again unlocks movement and emits `player_stood`.
|
|
|
|
signal player_seated
|
|
signal player_stood
|
|
|
|
@export var seat_transform_path: NodePath
|
|
@export var lerp_duration: float = 0.6
|
|
|
|
@onready var prompt_label: Label = $PromptLayer/PromptLabel
|
|
@onready var seat_marker: Node3D = get_node_or_null(seat_transform_path)
|
|
|
|
var _player: PlayerController = null
|
|
var _player_in_range: bool = false
|
|
var _is_seated: bool = false
|
|
var _stand_transform: Transform3D
|
|
var _tween: Tween = null
|
|
|
|
|
|
func _ready() -> void:
|
|
if prompt_label:
|
|
prompt_label.visible = false
|
|
body_entered.connect(_on_body_entered)
|
|
body_exited.connect(_on_body_exited)
|
|
|
|
|
|
func _on_body_entered(body: Node3D) -> void:
|
|
if body is PlayerController:
|
|
_player = body
|
|
_player_in_range = true
|
|
_update_prompt()
|
|
|
|
|
|
func _on_body_exited(body: Node3D) -> void:
|
|
if body == _player and not _is_seated:
|
|
_player_in_range = false
|
|
_player = null
|
|
_update_prompt()
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if not event.is_action_pressed("interact"):
|
|
return
|
|
if _is_seated:
|
|
_stand_up()
|
|
elif _player_in_range and _player != null:
|
|
_sit_down()
|
|
|
|
|
|
func _update_prompt() -> void:
|
|
if not prompt_label:
|
|
return
|
|
if _is_seated:
|
|
prompt_label.text = "Press E to stand"
|
|
prompt_label.visible = true
|
|
elif _player_in_range:
|
|
prompt_label.text = "Press E to sit"
|
|
prompt_label.visible = true
|
|
else:
|
|
prompt_label.visible = false
|
|
|
|
|
|
func _sit_down() -> void:
|
|
if seat_marker == null:
|
|
push_warning("ChairInteraction: no seat marker assigned; cannot sit.")
|
|
return
|
|
_is_seated = true
|
|
_stand_transform = _player.global_transform
|
|
_player.set_movement_locked(true)
|
|
_update_prompt()
|
|
_lerp_player_to(seat_marker.global_transform, func() -> void:
|
|
player_seated.emit()
|
|
)
|
|
|
|
|
|
func _stand_up() -> void:
|
|
_is_seated = false
|
|
_update_prompt()
|
|
_lerp_player_to(_stand_transform, func() -> void:
|
|
if _player:
|
|
_player.set_movement_locked(false)
|
|
player_stood.emit()
|
|
# Refresh range state after standing.
|
|
_player_in_range = overlaps_body(_player) if _player else false
|
|
_update_prompt()
|
|
)
|
|
|
|
|
|
func _lerp_player_to(target: Transform3D, on_done: Callable) -> void:
|
|
if _tween and _tween.is_running():
|
|
_tween.kill()
|
|
_tween = create_tween()
|
|
_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
|
|
_tween.tween_method(_apply_player_transform.bind(_player.global_transform, target),
|
|
0.0, 1.0, lerp_duration)
|
|
_tween.tween_callback(on_done)
|
|
|
|
|
|
func _apply_player_transform(t: float, from_xform: Transform3D, to_xform: Transform3D) -> void:
|
|
if _player:
|
|
_player.global_transform = from_xform.interpolate_with(to_xform, t)
|