# Hurry Curry! - a game about cooking # Copyright 2024 tpart # Copyright 2024 nokoe # # 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 . # extends Control class_name PopupMessage const SERVER_MESSAGE_SCENE = preload("res://menu/communicate/popup_message/server_message.tscn") var is_ingame := false var is_joined := false var positional_messages = {} @onready var positional_messages_node: Control = $Positional @onready var server_msg = $Static/VBox/ServerMessage @onready var hint_msg = $Static/VBox/HintMessage @onready var server_msg_label: Label = $Static/VBox/ServerMessage/CenterContainer/Label @onready var hint_msg_label: Label = $Static/VBox/HintMessage/CenterContainer/Label @onready var auto_hint_timers: Node = $Timers/AutoHints @onready var server_msg_timer: Timer = $Timers/Server @onready var hint_msg_timer: Timer = $Timers/Hint @onready var reset_timer = $Timers/Reset @onready var join_while_running_timer = $Timers/JoinWhileRunning @onready var game: Game = $"../Game" func _ready(): game.join_state_updated.connect(func(state: Game.JoinState): is_joined = state == Game.JoinState.JOINED ) game.update_tutorial_running.connect( func a(running: bool): if running: stop_game_hints() else: update_state() ) game.in_lobby_updated.connect( func a(in_lobby): is_ingame = not in_lobby update_state() ) func _process(_delta: float): for pos: Vector2 in positional_messages.keys(): var msg: PositionalMessage = positional_messages[pos] var pos_3d = Vector3(pos.x + 0.5, 1.5, pos.y + 0.5) var pos_2d = get_viewport().get_camera_3d().unproject_position(pos_3d) msg.node_2d.position = pos_2d.clamp( Vector2.ZERO + 0.5 * msg.node.size, Vector2(get_viewport_rect().size) - 0.5 * msg.node.size ) if msg.node.size != msg.last_size: msg.last_size = msg.node.size msg.node.position = -0.5 * msg.last_size func update_state(): if is_ingame and is_joined: start_game_hints() elif is_ingame: stop_game_hints() join_while_running_timer.start() else: stop_game_hints() func display_server_msg(msg: String, auto_remove := true): server_msg.show() server_msg_label.text = msg if auto_remove: server_msg_timer.start() func _on_server_timeout() -> void: clear_server_msg() func display_server_msg_positional(text: String, pos: Vector2, use_monospace: bool): var msg := PositionalMessage.new() msg.node = SERVER_MESSAGE_SCENE.instantiate() msg.node_2d = Node2D.new() positional_messages_node.add_child(msg.node_2d) msg.node_2d.add_child(msg.node) msg.node.set_text(text, use_monospace) msg.node.size = Vector2.ZERO msg.position = pos positional_messages[pos] = msg func clear_server_msg(position_ = null): if position_ == null: server_msg_timer.stop() server_msg.hide() else: if position_ in positional_messages: var msg: PositionalMessage = positional_messages[position_] msg.node_2d.queue_free() positional_messages.erase(position_) func display_hint_msg(msg: String): hint_msg.show() hint_msg_label.text = msg hint_msg_timer.start() func _on_hint_timer_timeout(): hint_msg.hide() func start_game_hints(): for c: Timer in auto_hint_timers.get_children(): c.start() func stop_game_hints(): _on_hint_timer_timeout() for c: Timer in auto_hint_timers.get_children(): c.stop() reset_timer.stop() join_while_running_timer.stop() func _input(_event): if Input.is_action_just_pressed("boost"): Global.set_hint("has_boosted", true) if any_action_just_pressed(["forwards", "backwards", "left", "right"]): Global.set_hint("has_moved", true) if any_action_just_pressed(["rotate_left", "rotate_right", "rotate_up", "rotate_down"]): if not Global.get_hint("has_reset"): reset_timer.start() Global.set_hint("has_rotated", true) if any_action_just_pressed(["zoom_in", "zoom_out"]): Global.set_hint("has_zoomed", true) if Input.is_action_just_pressed("interact_left") or Input.is_action_just_pressed("interact_right"): Global.set_hint("has_interacted", true) if Input.is_action_just_pressed("reset"): Global.set_hint("has_reset", true) func _on_boost_timeout(): if not Global.get_hint("has_boosted") and not Global.using_touch: display_hint_msg(tr("c.hint.boost").format([display_keybind("boost")])) func _on_move_timeout(): if not Global.get_hint("has_moved") and not Global.using_touch: display_hint_msg(tr("c.hint.movement").format([", ".join( [ display_keybind("forwards"), display_keybind("left"), display_keybind("backwards"), display_keybind("right") ] )])) func _on_interact_timeout(): if not Global.get_hint("has_interacted") and not Global.using_touch: display_hint_msg(tr("c.hint.interact").format([display_keybind("interact")])) func _on_reset_timeout(): if not Global.get_hint("has_reset") and not Global.using_touch: display_hint_msg(tr("c.hint.reset_camera").format([display_keybind("reset")])) func _on_zoom_timeout(): if not Global.get_hint("has_zoomed") and not Global.using_touch: display_hint_msg(tr("c.hint.zoom_camera").format([", ".join( [ display_keybind("zoom_in"), display_keybind("zoom_out") ] )])) func display_keybind(action_name: String) -> String: var events := InputManager.get_events(action_name) if events.size() == 0: # There are no events which match the action return tr("c.settings.input.unknown_event") for event: InputEvent in events: # Try to find event which matches input method var type := InputManager.get_event_type(event) if Global.using_joypad and type != InputManager.EventType.JOYPAD: continue if Global.using_touch and type != InputManager.EventType.TOUCH: continue return InputManager.display_input_event(event) # No matching event found. Just show any event. return InputManager.display_input_event(events[0]) func any_action_just_pressed(actions: Array) -> bool: for a: String in actions: if Input.is_action_just_pressed(a): return true return false func _on_rotate_camera_timeout(): if not Global.get_hint("has_rotated") and not Global.using_touch: display_hint_msg(tr("c.hint.rotate").format([", ".join( [ display_keybind("rotate_up"), display_keybind("rotate_left"), display_keybind("rotate_down"), display_keybind("rotate_right") ] )])) func _on_join_while_running_timeout(): if not game.join_state == Game.JoinState.JOINED and not Global.get_hint("has_seen_join_while_running"): Global.set_hint("has_seen_join_while_running", true) display_hint_msg(tr("c.hint.join_while_running").format([display_keybind("menu")])) func _on_performance_timeout() -> void: if not Global.get_hint("has_seen_performance") and Engine.get_frames_per_second() < DisplayServer.screen_get_refresh_rate() * 0.75: Global.set_hint("has_seen_performance", true) display_hint_msg(tr("c.hint.framerate_low")) class PositionalMessage: var node: ServerMessage var node_2d: Node2D var position: Vector2 var last_size: Vector2