# Hurry Curry! - a game about cooking # Copyright (C) 2025 Hurry Curry! contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, version 3 of the License only. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # class_name Item extends Node3D const CHECKMARK: PackedScene = preload("uid://bdbw8whs3data") var owned_by: Node3D var base: Node3D = Node3D.new() var progress_instance: Progress3D = preload("res://map/progress/progress.tscn").instantiate() var take_sound: PlayRandom = preload("res://audio/play_random.tscn").instantiate() var put_sound: PlayRandom = preload("res://audio/play_random.tscn").instantiate() var beep_sound := AudioStreamPlayer3D.new() var sound_id var progress_speed := 0. var progress_position := 0. var progress_warn := false var destroy_timeout = null var creation_timer = 0.0 var item_owned = false var player_owned_timer = 0.0 func _init(owned_by_: Node3D): progress_instance.position.y = 1 progress_instance.visible = false add_child(progress_instance) take_sound.volume_db = -16 put_sound.volume_db = -16 add_child(take_sound) add_child(put_sound) beep_sound.stream = preload("res://map/tiles/sounds/beep.ogg") add_child(beep_sound) setup_sounds() @warning_ignore("static_called_on_instance") base.position = base_position() base.name = "Base" add_child(base) owned_by = owned_by_ if not owned_by.get_parent() is Item and not owned_by is Item: scale = Vector3.ONE * 0.001 # setting to zero breaks assertions somewhere in the engine func _process(delta): if not is_instance_valid(owned_by): return if owned_by.get_parent() is Item or owned_by is Item: return var player_owned = owned_by.get_parent().get_parent() is Player player_owned_timer = player_owned_timer + delta if player_owned else 0. var anim_speed = 10.0 * exp(player_owned_timer * 3.0) # infinity is fine. G.interpolate can handle it position = G.interpolate(position, owned_by.global_position, delta * anim_speed) if player_owned: rotation.y = G.interpolate_angle(rotation.y, owned_by.global_rotation.y, delta * anim_speed) else: rotation.y = G.interpolate_angle_closest_quarter(rotation.y, owned_by.global_rotation.y, delta * anim_speed) if creation_timer != null: creation_timer += delta * 10.0 if creation_timer > 1: scale = Vector3.ONE creation_timer = null else: scale = Vector3.ONE * creation_timer if destroy_timeout != null: destroy_timeout -= delta * 5.0 if is_instance_valid(progress_instance): progress_instance.hide() if destroy_timeout <= 0: queue_free() else: scale = Vector3.ONE * destroy_timeout if !Global.game_paused: progress_position += delta * progress_speed progress_instance.update(progress_position, progress_warn) var time_remaining = (1 - progress_position) / progress_speed if progress_warn and progress_speed > 0 and time_remaining < 5.: if not beep_sound.playing: beep_sound.play() else: beep_sound.stop() else: beep_sound.stop() func progress(position_: float, speed: float, warn: bool): progress_instance.visible = true progress_position = position_ progress_speed = speed progress_warn = warn printt("progress", position_, speed, warn) if position_ == 1.0: # Progress gets called with position 1.0 when the task is finished if not warn: # Task finished succesfully var checkmark: CPUParticles3D = CHECKMARK.instantiate() owned_by.add_child(checkmark) checkmark.position.y = 0.5 checkmark.emitting = true var ding_sound := AudioStreamPlayer3D.new() owned_by.add_child(ding_sound) ding_sound.stream = preload("res://map/tiles/sounds/ding.ogg") ding_sound.play() else: # Task failed, food burned var burn_sound := AudioStreamPlayer3D.new() owned_by.add_child(burn_sound) burn_sound.stream = preload("res://map/tiles/sounds/burn.ogg") burn_sound.volume_db = -2 burn_sound.play() func finish(): progress_instance.visible = false if sound_id != null: Sound.item_finished(sound_id) func setup_sounds(): take_sound.setup([preload("res://map/items/sounds/generic_take.ogg")]) put_sound.setup([preload("res://map/items/sounds/plate_put.ogg")]) func remove(): destroy_timeout = 1 func take(): take_sound.play_random() func put(): put_sound.play_random() static func base_position() -> Vector3: return Vector3(0., 0., 0.) static func height() -> float: return .1