extends PanelContainer @onready var _screen = $PanelMargin/PanelColumn/Screen @onready var _close_button: Button = $PanelMargin/PanelColumn/CloseButton var current_floor: int = EventBus.STARTING_FLOOR var saved_count := 0 var doors_closing_flag := false var _onboarded := false const BASE_SURVIVORS := 2 const SURVIVORS_PER_FLOOR_INCREASE := 1 var survivors_remaining := 0 const THRESHOLD := 2 var score := 0 const POINTS_PER_PERSON := 100 const MOVING_ZONE_SPEED_MIN := 20.0 const MOVING_ZONE_SPEED_MAX := 130.0 const DIFFICULTY_EXPONENT := 1.4 const ROBOT_SPEED_TOP := 2.0 const ROBOT_SPEED_PER_FLOOR := 0.15 const ROBOT_DELAY_TOP := 3.0 const ROBOT_DELAY_PER_FLOOR := 0.6 const ROBOT_DELAY_MIN := 1.0 var people_in_elevator := 0 const PERFECT_STUN_DURATION := 1.5 const DING_TO_DOORS_DELAY := 2.0 func _ready(): _close_button.text = "CLOSE" _close_button.pressed.connect(_on_block_pressed) _screen.pulse_started.connect(_on_pulse_started) _screen.pulse_blocked.connect(_on_pulse_blocked) _screen.pulse_blocked_perfect.connect(_on_pulse_blocked_perfect) _screen.doors_closing.connect(func(): _on_doors_closing(true)) EventBus.game_started.connect(_start_floor) EventBus.game_lost.connect(func(_reason): $SfxRobotIUnderstand.play()) EventBus.survivor_squeaked_in.connect(_on_survivor_squeaked_in) EventBus.robot_close_warning.connect(_on_robot_close_warning) func _unhandled_input(event): if event is InputEventKey and event.pressed and not event.echo: if event.keycode == KEY_SPACE: _on_block_pressed() elif event.keycode == KEY_R: get_tree().reload_current_scene() elif event.keycode >= KEY_1 and event.keycode <= KEY_9: EventBus.debug_starting_floor = event.keycode - KEY_0 get_tree().reload_current_scene() elif event.keycode == KEY_0: EventBus.debug_starting_floor = EventBus.STARTING_FLOOR get_tree().reload_current_scene() func _reset_floor_state(): doors_closing_flag = false people_in_elevator = 0 _close_button.text = "CLOSE" var floors_remaining = current_floor - 1 survivors_remaining = BASE_SURVIVORS + (floors_remaining * SURVIVORS_PER_FLOOR_INCREASE) func _start_floor(): if EventBus.debug_starting_floor > 0: current_floor = EventBus.debug_starting_floor _onboarded = true EventBus.debug_starting_floor = 0 $SfxBell.play() if _onboarded and randf() < 0.4: $SfxRobotDeepBreath.play() _reset_floor_state() 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) EventBus.floor_started.emit(survivors_remaining) var floors_descended = EventBus.STARTING_FLOOR - current_floor var robot_speed = ROBOT_SPEED_TOP + floors_descended * ROBOT_SPEED_PER_FLOOR var robot_delay = max(ROBOT_DELAY_MIN, ROBOT_DELAY_TOP - floors_descended * ROBOT_DELAY_PER_FLOOR) EventBus.robot_floor_started.emit(robot_delay, robot_speed) _screen.start(current_floor) var t_raw = float(floors_descended) / float(EventBus.STARTING_FLOOR - 1) var t_difficulty = pow(t_raw, DIFFICULTY_EXPONENT) var zone_speed = lerp(MOVING_ZONE_SPEED_MIN, MOVING_ZONE_SPEED_MAX, t_difficulty) _screen.set_block_zone_movement(zone_speed) if not _onboarded: _onboarded = true 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: $SfxRobotSoundsDifficult.play() func _on_robot_close_warning(): if not $SfxRobotDeepBreath.playing: $SfxRobotDeepBreath.play() func _on_block_pressed(): if doors_closing_flag: return EventBus.block_pressed.emit() if _screen.pulse_active: _screen.attempt_block() else: $SfxRobotThankYou.play() _on_doors_closing(false) func _on_pulse_started(duration: float): _close_button.text = "BLOCK" EventBus.pulse_started.emit(duration) func _on_pulse_blocked_perfect(): EventBus.robot_stun_requested.emit(PERFECT_STUN_DURATION) func _on_pulse_blocked(): _close_button.text = "CLOSE" EventBus.pulse_blocked.emit() survivors_remaining -= 1 people_in_elevator += 1 $SfxDing.play() EventBus.people_changed.emit(people_in_elevator, THRESHOLD) if survivors_remaining <= 0: get_tree().create_timer(0.25, false).timeout.connect(_on_doors_closing, CONNECT_ONE_SHOT) return var gap = _screen.get_pulse_gap() get_tree().create_timer(gap, false).timeout.connect( func(): if not doors_closing_flag: _screen.launch_pulse(), CONNECT_ONE_SHOT ) func _on_doors_closing(fast: bool = false): if doors_closing_flag: return doors_closing_flag = true EventBus.doors_closed.emit(fast) if people_in_elevator < THRESHOLD: _screen.show_loss("TOO FEW") EventBus.game_lost.emit("TOO FEW") return var base_points = people_in_elevator * POINTS_PER_PERSON var bonus = max(0, people_in_elevator - THRESHOLD) * POINTS_PER_PERSON score += base_points + bonus saved_count += people_in_elevator EventBus.score_changed.emit(score) EventBus.saved_changed.emit(saved_count) current_floor -= 1 if current_floor <= 1: _screen.show_win() EventBus.floor_changed.emit(current_floor) EventBus.game_won.emit() return $SfxClose.play() _screen.show_countdown() _screen.shrink_block_zone() var tween = create_tween() tween.tween_interval(3.0) tween.tween_callback(_start_floor)