diff --git a/audio/RoboZacSpeaker.wav b/audio/RoboZacSpeaker.wav new file mode 100644 index 0000000..8772203 Binary files /dev/null and b/audio/RoboZacSpeaker.wav differ diff --git a/audio/RoboZacSpeaker.wav.import b/audio/RoboZacSpeaker.wav.import new file mode 100644 index 0000000..5444170 --- /dev/null +++ b/audio/RoboZacSpeaker.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://cnfmytsyo8biq" +path="res://.godot/imported/RoboZacSpeaker.wav-f05e9451bbf465ad55d22d78b38e2297.sample" + +[deps] + +source_file="res://audio/RoboZacSpeaker.wav" +dest_files=["res://.godot/imported/RoboZacSpeaker.wav-f05e9451bbf465ad55d22d78b38e2297.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=1 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=2 diff --git a/scenes/elevator.gd b/scenes/elevator.gd index b76743d..a1db543 100644 --- a/scenes/elevator.gd +++ b/scenes/elevator.gd @@ -5,8 +5,14 @@ const DOOR_CLOSED_X := 0.7 const DOOR_DEFAULT_TIME := 3.0 const DOOR_FAST_CLOSE_TIME := 1.0 const DOOR_REOPEN_TIME := 0.4 +const PULSE_CLOSE_LAG_TOP := 1.0 +const PULSE_CLOSE_LAG_PER_FLOOR := 0.09 +const PULSE_CLOSE_LAG_MIN := 0.2 +const DOORS_NEARLY_OPEN_LEAD := 0.4 var _tween: Tween = null +var _pulse_close_pending: bool = false +var _current_floor: int = EventBus.STARTING_FLOOR func _ready(): $ElevatorDoorRight.position = Vector3(DOOR_CLOSED_X, 0, 0) @@ -16,21 +22,39 @@ func _ready(): EventBus.doors_closed.connect(_on_doors_closed) EventBus.pulse_started.connect(_on_pulse_started) EventBus.pulse_blocked.connect(_on_pulse_blocked) + EventBus.floor_changed.connect(func(f): _current_floor = f) func _on_doors_opened(): + _pulse_close_pending = false _set_door_collision(false) _tween_doors(DOOR_OPEN_X, DOOR_DEFAULT_TIME) + _tween.chain().tween_callback(func(): EventBus.doors_fully_opened.emit()) + get_tree().create_timer(DOOR_DEFAULT_TIME - DOORS_NEARLY_OPEN_LEAD, false).timeout.connect( + func(): EventBus.doors_nearly_opened.emit(), + CONNECT_ONE_SHOT + ) func _on_doors_closed(fast: bool): + _pulse_close_pending = false _set_door_collision(true) _tween_doors(DOOR_CLOSED_X, DOOR_FAST_CLOSE_TIME if fast else DOOR_DEFAULT_TIME) _tween.chain().tween_callback(func(): EventBus.doors_fully_closed.emit()) func _on_pulse_started(duration: float): _set_door_collision(true) - _tween_doors(DOOR_CLOSED_X, duration) + _pulse_close_pending = true + var floors_descended = EventBus.STARTING_FLOOR - _current_floor + var lag = max(PULSE_CLOSE_LAG_MIN, PULSE_CLOSE_LAG_TOP - floors_descended * PULSE_CLOSE_LAG_PER_FLOOR) + get_tree().create_timer(lag, false).timeout.connect( + func(): + if _pulse_close_pending: + _pulse_close_pending = false + _tween_doors(DOOR_CLOSED_X, duration), + CONNECT_ONE_SHOT + ) func _on_pulse_blocked(): + _pulse_close_pending = false _set_door_collision(false) _tween_doors(DOOR_OPEN_X, DOOR_REOPEN_TIME) diff --git a/scenes/elevator_panel.gd b/scenes/elevator_panel.gd index 9b541eb..63cf0a4 100644 --- a/scenes/elevator_panel.gd +++ b/scenes/elevator_panel.gd @@ -30,7 +30,7 @@ const ROBOT_DELAY_MIN := 1.0 var people_in_elevator := 0 const PERFECT_STUN_DURATION := 1.5 -const PRE_PULSE_DELAY := 3.5 +const DING_TO_DOORS_DELAY := 2.0 func _ready(): _close_button.text = "CLOSE" @@ -72,12 +72,18 @@ func _start_floor(): _onboarded = true EventBus.debug_starting_floor = 0 - $SfxOpen.play() $SfxBell.play() if _onboarded and randf() < 0.4: $SfxRobotDeepBreath.play() _reset_floor_state() - EventBus.doors_opened.emit() + get_tree().create_timer(DING_TO_DOORS_DELAY, false).timeout.connect( + func(): + if not is_instance_valid(self) or doors_closing_flag: + return + $SfxOpen.play() + EventBus.doors_opened.emit(), + CONNECT_ONE_SHOT + ) EventBus.people_changed.emit(people_in_elevator, THRESHOLD) EventBus.floor_changed.emit(current_floor) @@ -97,23 +103,13 @@ func _start_floor(): if not _onboarded: _onboarded = true - _screen.show_onboarding("BLOCK\nIN GREEN ZONE") - get_tree().create_timer(3.0, false).timeout.connect( - func(): - if not is_instance_valid(_screen): - return - _screen.end_onboarding() - _screen.launch_pulse(), - CONNECT_ONE_SHOT - ) - else: - get_tree().create_timer(PRE_PULSE_DELAY, false).timeout.connect( - func(): - if not is_instance_valid(self) or doors_closing_flag: - return - _screen.launch_pulse(), - CONNECT_ONE_SHOT - ) + EventBus.doors_nearly_opened.connect( + func(): + if not is_instance_valid(self) or doors_closing_flag: + return + _screen.launch_pulse(), + CONNECT_ONE_SHOT + ) func _on_survivor_squeaked_in(): if not $SfxRobotSoundsDifficult.playing: @@ -126,6 +122,7 @@ func _on_robot_close_warning(): func _on_block_pressed(): if doors_closing_flag: return + EventBus.block_pressed.emit() if _screen.pulse_active: _screen.attempt_block() else: diff --git a/scenes/game.gd b/scenes/game.gd index 62dcfd7..b760fea 100644 --- a/scenes/game.gd +++ b/scenes/game.gd @@ -2,3 +2,4 @@ extends Node3D func _ready() -> void: $ComponentSpawn.survivor_spawn = $World/SurvivorSpawn + $Ambience.finished.connect($Ambience.play) diff --git a/scenes/game.tscn b/scenes/game.tscn index 4c7222b..566f223 100644 --- a/scenes/game.tscn +++ b/scenes/game.tscn @@ -17,6 +17,8 @@ [ext_resource type="PackedScene" uid="uid://sgakdvtoblmd" path="res://scenes/title_screen.tscn" id="11_title"] [ext_resource type="AudioStream" uid="uid://b3d6rntbosvc6" path="res://audio/Ambience.wav" id="12_amb"] [ext_resource type="PackedScene" path="res://scenes/pause_menu.tscn" id="12_pause"] +[ext_resource type="AudioStream" uid="uid://cnfmytsyo8biq" path="res://audio/RoboZacSpeaker.wav" id="13_muzak"] +[ext_resource type="Script" path="res://scenes/muzak.gd" id="14_muzak_s"] [node name="Game" type="Node3D" unique_id=1456297160] script = ExtResource("1_lbhrr") @@ -66,6 +68,11 @@ stream = ExtResource("12_amb") volume_db = -6.0 autoplay = true +[node name="Muzak" type="AudioStreamPlayer" parent="." unique_id=1100000006] +stream = ExtResource("13_muzak") +volume_db = -10.0 +script = ExtResource("14_muzak_s") + [node name="ComponentSpawn" parent="." unique_id=649225939 instance=ExtResource("9_0tnpc")] [node name="EndScreen" parent="." unique_id=993175156 instance=ExtResource("10_endsc")] diff --git a/scenes/muzak.gd b/scenes/muzak.gd new file mode 100644 index 0000000..871f116 --- /dev/null +++ b/scenes/muzak.gd @@ -0,0 +1,64 @@ +extends AudioStreamPlayer + +const NORMAL_DB := -10.0 +const DUCKED_DB := -24.0 +const DUCK_IN := 0.15 +const DUCK_OUT := 0.4 +# these paths wwould need to be updated if renamed or moved +const BARK_PATHS := [ + "../CanvasPanel/ElevatorPanel/SfxRobotDeepBreath", + "../CanvasPanel/ElevatorPanel/SfxRobotSoundsDifficult", + "../CanvasPanel/ElevatorPanel/SfxRobotIUnderstand", + "../CanvasPanel/ElevatorPanel/SfxRobotThankYou", +] + +var _barks: Array = [] +var _ducked: bool = false +var _tween: Tween +var _started: bool = false + +func _ready() -> void: + volume_db = NORMAL_DB + finished.connect(play) + for p in BARK_PATHS: + var n := get_node_or_null(p) + if n: + _barks.append(n) + EventBus.game_started.connect(_on_game_started) + EventBus.game_won.connect(_on_game_ended) + EventBus.game_lost.connect(_on_game_lost) + +func _process(_delta: float) -> void: + if not playing: + return + var any := false + for b in _barks: + if b.playing: + any = true + break + if any and not _ducked: + _ducked = true + _to_db(DUCKED_DB, DUCK_IN) + elif not any and _ducked: + _ducked = false + _to_db(NORMAL_DB, DUCK_OUT) + +func _to_db(target: float, time: float) -> void: + if _tween: + _tween.kill() + _tween = create_tween() + _tween.tween_property(self, "volume_db", target, time) + +func _on_game_started() -> void: + if _started: + return + _started = true + _ducked = false + volume_db = NORMAL_DB + play() + +func _on_game_ended() -> void: + stop() + +func _on_game_lost(_reason) -> void: + stop() diff --git a/scenes/muzak.gd.uid b/scenes/muzak.gd.uid new file mode 100644 index 0000000..b2ae58e --- /dev/null +++ b/scenes/muzak.gd.uid @@ -0,0 +1 @@ +uid://deyjxii7yykjv diff --git a/scenes/robot.gd b/scenes/robot.gd index fadf9fe..2924016 100644 --- a/scenes/robot.gd +++ b/scenes/robot.gd @@ -6,7 +6,7 @@ const STALK_ILLUMINATE_DISTANCE := 15.0 var robot_ready: bool = false var robot_win: bool = false var speed: float = 1.0 -var doors_open: bool = false +var doors_open: bool = true var stun_remaining: float = 0.0 var _stalking_close: bool = false diff --git a/scenes/survivor.gd b/scenes/survivor.gd index 9dd2551..679d92e 100644 --- a/scenes/survivor.gd +++ b/scenes/survivor.gd @@ -7,11 +7,16 @@ const CHASE_LONG := preload("res://audio/Chase1.wav") const CHASE_TRACKS := [CHASE_SHORT_1, CHASE_SHORT_2, CHASE_MID, CHASE_LONG] static var _last_chase: AudioStream = null +const SCREAM_OPEN_DB := 0.0 +const SCREAM_CLOSED_DB := -20.0 + var speed: int = 3 var clumsiness: int = 0 var _saved: bool = false +var _in_safety_zone: bool = false @onready var safety_zone: Node = get_node_or_null("/root/Game/World/ElevatorSafeZone") +@onready var _elevator: Node = safety_zone.get_node_or_null("Elevator") if safety_zone else null #func start(xform): @@ -30,16 +35,31 @@ func _ready(): ) func _physics_process(_delta): - velocity.z = -speed + var p: float = _elevator.get_door_close_progress() if _elevator else 0.0 + if _in_safety_zone and not _saved and p > 0.49: + velocity.z = 0 + else: + velocity.z = -speed move_and_slide() + if _elevator: + $ScreamPlayer.volume_db = lerp(SCREAM_OPEN_DB, SCREAM_CLOSED_DB, p) func _on_area_3d_area_entered(area: Area3D) -> void: - if area == safety_zone and not _saved: - _saved = true + if area == safety_zone and not _in_safety_zone: + _in_safety_zone = true var elevator = safety_zone.get_node_or_null("Elevator") - if elevator and elevator.get_door_close_progress() > 0.7: - EventBus.survivor_squeaked_in.emit() + var close_progress: float = elevator.get_door_close_progress() if elevator else 0.0 + if close_progress > 0.49: + return get_tree().create_timer(0.5, false).timeout.connect( - func(): queue_free(), + func(): + if not is_instance_valid(self): + return + var elev = safety_zone.get_node_or_null("Elevator") + var final_progress: float = elev.get_door_close_progress() if elev else 0.0 + if final_progress > 0.49: + return + _saved = true + queue_free(), CONNECT_ONE_SHOT ) diff --git a/scenes/virtua_hand.gd b/scenes/virtua_hand.gd new file mode 100644 index 0000000..76cfed0 --- /dev/null +++ b/scenes/virtua_hand.gd @@ -0,0 +1,25 @@ +extends Sprite3D + +const UP_DURATION := 0.1 +const HOLD_DURATION := 0.05 +const DOWN_DURATION := 0.18 + +var _rest_position: Vector3 +var _tween: Tween + +@onready var _button: Node3D = get_parent().get_node("ElevatorButton") + +func _ready() -> void: + _rest_position = position + EventBus.block_pressed.connect(_animate_press) + +func _animate_press() -> void: + if not is_instance_valid(_button): + return + if _tween and _tween.is_valid(): + _tween.kill() + var press_pos := Vector3(_rest_position.x, _button.position.y, _rest_position.z) + _tween = create_tween() + _tween.tween_property(self, "position", press_pos, UP_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT) + _tween.tween_interval(HOLD_DURATION) + _tween.tween_property(self, "position", _rest_position, DOWN_DURATION).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN) diff --git a/scenes/virtua_hand.gd.uid b/scenes/virtua_hand.gd.uid new file mode 100644 index 0000000..7629b6b --- /dev/null +++ b/scenes/virtua_hand.gd.uid @@ -0,0 +1 @@ +uid://by5qr8pax54b1 diff --git a/scenes/virtua_hand.tscn b/scenes/virtua_hand.tscn index b7fae54..ee5014a 100644 --- a/scenes/virtua_hand.tscn +++ b/scenes/virtua_hand.tscn @@ -1,8 +1,10 @@ [gd_scene format=3 uid="uid://bkqwi2yqa0nvg"] [ext_resource type="Texture2D" uid="uid://51p1gbyn5l02" path="res://images/virtua_hand.png" id="1_ikq7c"] +[ext_resource type="Script" path="res://scenes/virtua_hand.gd" id="2_hand_s"] [node name="VirtuaHand" type="Sprite3D" unique_id=1811028460] billboard = 1 texture_filter = 0 texture = ExtResource("1_ikq7c") +script = ExtResource("2_hand_s") diff --git a/scenes/world.tscn b/scenes/world.tscn index df8e683..43df538 100644 --- a/scenes/world.tscn +++ b/scenes/world.tscn @@ -58,7 +58,7 @@ unit_size = 4.0 max_distance = 30.0 [node name="CollisionShape3D" type="CollisionShape3D" parent="ElevatorSafeZone" unique_id=264489586] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.24584353, 2.8164063, -0.56969166) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.24584353, 2.8164063, -0.49238968) shape = SubResource("BoxShape3D_k0juu") [node name="SurvivorSpawn" type="Marker3D" parent="." unique_id=1095768768] diff --git a/scripts/event_bus.gd b/scripts/event_bus.gd index 168d13d..2f58ae2 100644 --- a/scripts/event_bus.gd +++ b/scripts/event_bus.gd @@ -15,6 +15,8 @@ signal game_won signal game_lost(reason: String) signal floor_started(survivor_count: int) signal doors_opened +signal doors_nearly_opened +signal doors_fully_opened signal doors_closed(fast: bool) signal doors_fully_closed signal pulse_started(duration: float) @@ -23,5 +25,6 @@ signal robot_stun_requested(duration: float) signal robot_floor_started(delay: float, robot_speed: float) signal robot_close_warning signal survivor_squeaked_in +signal block_pressed @warning_ignore_restore("unused_signal")