From 90011bd75f3990810fafdf63eef833dc2a795422 Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Sat, 21 Jun 2025 14:35:32 +0100 Subject: [PATCH] Changes for backporting. --- addons/GodotWebHTTPHack/export_plugin.gd.uid | 1 + addons/GodotWebHTTPHack/plugin.gd.uid | 1 + addons/qr_code/bit_stream.gd.uid | 1 + addons/qr_code/plugin.gd.uid | 1 + addons/qr_code/qr_code.gd.uid | 1 + addons/qr_code/qr_code_rect.gd.uid | 1 + addons/qr_code/reed_solomon.gd.uid | 1 + addons/qr_code/shift_jis.gd.uid | 1 + objects/player.tscn | 2 +- scripts/announcer.gd | 65 +++++++++ scripts/announcer_line.gd | 7 + scripts/announcer_line.gd.uid | 1 + scripts/client.gd | 18 ++- scripts/client.gd.uid | 1 + scripts/host.gd | 1 + scripts/player.gd | 132 ++++++++++++++++--- scripts/player.gd.uid | 1 + scripts/players.gd | 58 +++++++- scripts/players.gd.uid | 1 + scripts/prompt.gd | 54 ++++++++ scripts/prompt.gd.uid | 1 + scripts/prompt_manager.gd | 81 ++++++++---- scripts/prompt_manager.gd.uid | 1 + scripts/proxy_delegate.gd | 2 +- scripts/proxy_delegate.gd.uid | 1 + scripts/util/center-pivot.gd | 9 ++ scripts/util/center-pivot.gd.uid | 1 + scripts/util/multi_await.gd | 33 +++++ scripts/util/multi_await.gd.uid | 1 + 29 files changed, 425 insertions(+), 54 deletions(-) create mode 100644 addons/GodotWebHTTPHack/export_plugin.gd.uid create mode 100644 addons/GodotWebHTTPHack/plugin.gd.uid create mode 100644 addons/qr_code/bit_stream.gd.uid create mode 100644 addons/qr_code/plugin.gd.uid create mode 100644 addons/qr_code/qr_code.gd.uid create mode 100644 addons/qr_code/qr_code_rect.gd.uid create mode 100644 addons/qr_code/reed_solomon.gd.uid create mode 100644 addons/qr_code/shift_jis.gd.uid create mode 100644 scripts/announcer.gd create mode 100644 scripts/announcer_line.gd create mode 100644 scripts/announcer_line.gd.uid create mode 100644 scripts/client.gd.uid create mode 100644 scripts/player.gd.uid create mode 100644 scripts/players.gd.uid create mode 100644 scripts/prompt.gd create mode 100644 scripts/prompt.gd.uid create mode 100644 scripts/prompt_manager.gd.uid create mode 100644 scripts/proxy_delegate.gd.uid create mode 100644 scripts/util/center-pivot.gd create mode 100644 scripts/util/center-pivot.gd.uid create mode 100644 scripts/util/multi_await.gd create mode 100644 scripts/util/multi_await.gd.uid diff --git a/addons/GodotWebHTTPHack/export_plugin.gd.uid b/addons/GodotWebHTTPHack/export_plugin.gd.uid new file mode 100644 index 0000000..765b7f3 --- /dev/null +++ b/addons/GodotWebHTTPHack/export_plugin.gd.uid @@ -0,0 +1 @@ +uid://dtrgx6wh8c1uh diff --git a/addons/GodotWebHTTPHack/plugin.gd.uid b/addons/GodotWebHTTPHack/plugin.gd.uid new file mode 100644 index 0000000..b5c9e5b --- /dev/null +++ b/addons/GodotWebHTTPHack/plugin.gd.uid @@ -0,0 +1 @@ +uid://lg3f8btt8wof diff --git a/addons/qr_code/bit_stream.gd.uid b/addons/qr_code/bit_stream.gd.uid new file mode 100644 index 0000000..24d9ccc --- /dev/null +++ b/addons/qr_code/bit_stream.gd.uid @@ -0,0 +1 @@ +uid://mucemjrqagns diff --git a/addons/qr_code/plugin.gd.uid b/addons/qr_code/plugin.gd.uid new file mode 100644 index 0000000..9c7d8bd --- /dev/null +++ b/addons/qr_code/plugin.gd.uid @@ -0,0 +1 @@ +uid://cyp6tctb4njop diff --git a/addons/qr_code/qr_code.gd.uid b/addons/qr_code/qr_code.gd.uid new file mode 100644 index 0000000..080dd6b --- /dev/null +++ b/addons/qr_code/qr_code.gd.uid @@ -0,0 +1 @@ +uid://b6tixx7tmkex5 diff --git a/addons/qr_code/qr_code_rect.gd.uid b/addons/qr_code/qr_code_rect.gd.uid new file mode 100644 index 0000000..e4c0ac0 --- /dev/null +++ b/addons/qr_code/qr_code_rect.gd.uid @@ -0,0 +1 @@ +uid://cewiul3aondnr diff --git a/addons/qr_code/reed_solomon.gd.uid b/addons/qr_code/reed_solomon.gd.uid new file mode 100644 index 0000000..36f498d --- /dev/null +++ b/addons/qr_code/reed_solomon.gd.uid @@ -0,0 +1 @@ +uid://bt8shmw5017b6 diff --git a/addons/qr_code/shift_jis.gd.uid b/addons/qr_code/shift_jis.gd.uid new file mode 100644 index 0000000..3baab49 --- /dev/null +++ b/addons/qr_code/shift_jis.gd.uid @@ -0,0 +1 @@ +uid://c2m86ih8y68pd diff --git a/objects/player.tscn b/objects/player.tscn index 846b93a..b525efd 100644 --- a/objects/player.tscn +++ b/objects/player.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=3 format=3 uid="uid://difcchtl3dx04"] -[ext_resource type="Script" path="res://scripts/player.gd" id="1_b212b"] +[ext_resource type="Script" uid="uid://ch1ox42pq5wl7" path="res://scripts/player.gd" id="1_b212b"] [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_v03xq"] properties/0/path = NodePath(".:session_id") diff --git a/scripts/announcer.gd b/scripts/announcer.gd new file mode 100644 index 0000000..8174ef9 --- /dev/null +++ b/scripts/announcer.gd @@ -0,0 +1,65 @@ +extends Node +class_name Announcer + +@onready var announcer_audio_player: AudioStreamPlayer = $"AnnouncerAudioPlayer" +@onready var animation: AnimationPlayer = $"../AnimationPlayer" + +@export_group("Announcer", "announcer") +@export_subgroup("Text", "announcer_text") +@export var announcer_text_wpm: float = 150.0 +@export var announcer_text_linger_ratio: float = 1.0 + +@export_subgroup("Lines", "announcer_lines") +@export var announcer_lines_intro: Array[AnnouncerLine] = [] +@export var announcer_lines_start_game: Array[AnnouncerLine] = [] +@export var announcer_lines_waiting_for_players: Array[AnnouncerLine] = [] +@export var announcer_lines_team_handout_pre: Array[AnnouncerLine] = [] +@export var announcer_lines_team_handout_post: Array[AnnouncerLine] = [] +@export var announcer_lines_role_handout_pre: Array[AnnouncerLine] = [] +@export var announcer_lines_role_handout_post: Array[AnnouncerLine] = [] + +signal finished() + +func _ready() -> void: + announcer_audio_player.connect("finished", func(): finished.emit()) + +func announce_line_by_id(id: String, context: Dictionary = {}) -> void: + var lines: Array[AnnouncerLine] = [] + lines.assign(get_indexed(NodePath("announcer_lines_" + id))) + if !lines.is_empty(): + announce_line(lines.pick_random(), context) + +func announce_text(text: String, context: Dictionary = {}) -> void: + var line: AnnouncerLine = AnnouncerLine.new() + line.text = text + await announce_line(line, context) + +func announce_random_line(lines: Array[AnnouncerLine], context: Dictionary = {}) -> void: + await announce_line(lines.pick_random(), context) + +func announce_line(line: AnnouncerLine, context: Dictionary = {}) -> void: + if line == null: + return + $"../SubtitlesLabel".text = line.text.format(context) + animation.play("subtitles_appear") + await animation.animation_finished + var duration: float = 1.0 + if line.audio == null: + line.audio = await $"../TTS".get_tts_audio(line.text.format(context)) + + if line.audio != null: + duration = line.audio.get_length() + announcer_audio_player.stream = line.audio + announcer_audio_player.play(0.0) + else: + var word_count = line.text.count(" ")+1 + duration = word_count * (60.0/150.0) + animation.play("subtitles_display", -1, 1.0/duration) + await animation.animation_finished + var linger_time: float = duration * announcer_text_linger_ratio + await get_tree().create_timer(linger_time).timeout + animation.play("subtitles_disappear") + await animation.animation_finished + +func is_speaking(): + return announcer_audio_player.playing diff --git a/scripts/announcer_line.gd b/scripts/announcer_line.gd new file mode 100644 index 0000000..a565954 --- /dev/null +++ b/scripts/announcer_line.gd @@ -0,0 +1,7 @@ +extends Resource +class_name AnnouncerLine + +@export_multiline var text: String +@export var audio: AudioStream +@export var interruptable: bool = true +@export var stop_time: bool = false diff --git a/scripts/announcer_line.gd.uid b/scripts/announcer_line.gd.uid new file mode 100644 index 0000000..d939110 --- /dev/null +++ b/scripts/announcer_line.gd.uid @@ -0,0 +1 @@ +uid://mnnaj7chmh0y diff --git a/scripts/client.gd b/scripts/client.gd index a04b122..06f9b58 100644 --- a/scripts/client.gd +++ b/scripts/client.gd @@ -2,6 +2,7 @@ extends Control @export var multiplayer_port: int = 2481 @export var reconnection_delay: float = 5 +@export var auto_setup: bool = false var server_ip: String = "127.0.0.1" @@ -15,6 +16,10 @@ var session_id: int = -1 var searching_for_player: bool = false +signal local_player_created(player: Player) + +@onready var players: Players = $"GameState/Players" + # Called when the node enters the scene tree for the first time. func _ready() -> void: server_ip = get_server_ip() @@ -25,7 +30,7 @@ func _ready() -> void: reconnect() - $"../Players".connect("player_joined", on_player_joined) + players.connect("player_joined", on_player_joined) func _process(delta: float) -> void: if !connected and !connecting: @@ -34,10 +39,15 @@ func _process(delta: float) -> void: reconnection_timer = 0 reconnect() if searching_for_player: - for player in $"../Players".get_children(): + for player in players.get_children(): if player.session_id == session_id: + print("Client %d found player object %s" % [session_id, player]) + if auto_setup: + player.player_name = "Bot %d" % session_id + player.player_pronouns = "they/them" searching_for_player = false - $PromptManager.player = player + local_player_created.emit(player) + #$PromptManager.player = player func reconnect() -> void: var peer: MultiplayerPeer = WebSocketMultiplayerPeer.new() @@ -92,7 +102,7 @@ func get_session_id() -> int: func join_game(session_id: int): searching_for_player = true - var player : Player = $"../Players".find_player_by_session_id(session_id) + var player : Player = players.find_player_by_session_id(session_id) #player.claim_authority(session_id) func on_player_joined(player: Player): diff --git a/scripts/client.gd.uid b/scripts/client.gd.uid new file mode 100644 index 0000000..c772c29 --- /dev/null +++ b/scripts/client.gd.uid @@ -0,0 +1 @@ +uid://c7s63vjvbbyit diff --git a/scripts/host.gd b/scripts/host.gd index bd19e22..a6ec9e1 100644 --- a/scripts/host.gd +++ b/scripts/host.gd @@ -38,6 +38,7 @@ func _ready() -> void: start_caddy() start_multiplayer() + func _process(delta: float) -> void: check_caddy_timer += delta diff --git a/scripts/player.gd b/scripts/player.gd index 5d78845..6101da7 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -5,34 +5,124 @@ class_name Player @export var player_name: String = "" @export var player_pronouns: String = "" -@export var current_prompt: Dictionary = {}: +var game_state: GameState = null + +var waiting_actions: Dictionary = {} +var prompt_queue: Array[Prompt] = [] +var message_context: Dictionary = {} + +var current_prompt: Prompt: set(val): if val != current_prompt: current_prompt = val prompt_changed.emit(current_prompt) + +var playing: bool = false: + set(val): + if val != playing: + playing = val + playing_status_changed.emit(playing) -signal prompt_changed(prompt: Dictionary) -signal prompt_answered(answer: String) +signal prompt_changed(prompt: Prompt) +signal prompt_answered(prompt: Prompt, answer: String) +signal prompt_queue_finished() +signal playing_status_changed(playing: bool) +signal message_spoken(message: String) -@rpc("any_peer", "call_local", "reliable") -func claim_authority(peer_id: int) -> void: - set_multiplayer_authority(peer_id, true) +#@rpc("any_peer", "call_local", "reliable") +#func claim_authority(peer_id: int) -> void: + #set_multiplayer_authority(peer_id, true) -func send_prompt(prompt: Dictionary) -> void: - _send_prompt.rpc(JSON.stringify(prompt)) - pass +func send_message(message: String, additional_context: Dictionary = {}) -> void: + var prompt: Prompt = Prompt.create(message, Prompt.PromptType.CONFIRMATION)\ + .with_context(message_context)\ + .with_context(additional_context) + send_prompt(prompt) + +func add_message_context(key: String, value: String) -> void: + message_context[key] = value + +func add_message_context_dict(context: Dictionary) -> void: + message_context.merge(context, true) + +func get_pronoun_context_dict(prefix: String = "") -> Dictionary: + var ret: Dictionary = {} + var they: String + var them: String + var their: String + var theirs: String + match player_pronouns: + "he/him": + they = "he" + them = "him" + their = "his" + theirs = "his" + "she/her": + they = "she" + them = "her" + their = "her" + theirs = "hers" + _: + they = "they" + them = "them" + their = "their" + theirs = "theirs" + ret[prefix+"they"] = they + ret[prefix+"them"] = them + ret[prefix+"their"] = their + ret[prefix+"theirs"] = theirs + ret[prefix+"themself"] = them+"self" + return ret + +func get_context_dict(prefix: String) -> Dictionary: + var ret = get_pronoun_context_dict(prefix) + ret[prefix+"name"] = player_name.capitalize() + ret[prefix+"name's"] = player_name.capitalize() + "'s" + return ret + +func send_action(action: Action, immediate: bool = false) -> void: + waiting_actions[action.prompt.id] = action + #connect("prompt_answered", action.prompt_answered.bind(self), CONNECT_ONE_SHOT) + send_prompt(action.prompt) + +func send_prompt(prompt: Prompt) -> void: + if prompt != null: + _send_prompt.rpc(JSON.stringify(prompt.save())) + else: + _send_prompt.rpc("{}") @rpc("any_peer", "call_local", "reliable") func _send_prompt(json_prompt: String) -> void: - pass - if !current_prompt.is_empty(): - submit_prompt_answer.rpc(1,"") - current_prompt = JSON.parse_string(json_prompt) - print("Player %d prompt received: \"%s\"" % [session_id, current_prompt["text"]]) - -@rpc("any_peer", "call_remote", "reliable") -func submit_prompt_answer(answer: String) -> void: - #current_prompt = null - current_prompt.clear() - prompt_answered.emit(answer) - print("Player %d answer received: \"%s\"" % [session_id, answer]) + print("Peer %d Player %d prompt received: %s" % [multiplayer.get_unique_id(),session_id, json_prompt]) + var prompt: Prompt = Prompt.load(JSON.parse_string(json_prompt)) + if current_prompt != null: + if current_prompt.interruptable: + submit_prompt_answer.rpc(current_prompt.id,"") + current_prompt = null + else: + prompt_queue.append(prompt) + if current_prompt == null: + current_prompt = prompt + if current_prompt != null: + current_prompt.context["my_name"] = name + #print("Peer %d Player %d prompt received: \"%s\" context: %s" % [multiplayer.get_unique_id(),session_id, current_prompt.text, current_prompt.context]) + +@rpc("any_peer", "call_local", "reliable") +func submit_prompt_answer(prompt_id: int, answer: String) -> void: + print("Peer %d Player %d answer received: \"%s\"" % [multiplayer.get_unique_id(),session_id, answer]) + prompt_answered.emit(current_prompt, answer) + if waiting_actions.has(prompt_id): + var action: Action = waiting_actions.get(prompt_id) + action.prompt_answered(answer,self) + waiting_actions.erase(prompt_id) + if prompt_queue.is_empty(): + current_prompt = null + prompt_queue_finished.emit() + else: + current_prompt = prompt_queue.pop_front() + +func speak(message: String) -> void: + message_spoken.emit(message) + +func is_busy() -> bool: + return current_prompt != null or !prompt_queue.is_empty() diff --git a/scripts/player.gd.uid b/scripts/player.gd.uid new file mode 100644 index 0000000..0462c1a --- /dev/null +++ b/scripts/player.gd.uid @@ -0,0 +1 @@ +uid://ch1ox42pq5wl7 diff --git a/scripts/players.gd b/scripts/players.gd index 83d853f..b3bd003 100644 --- a/scripts/players.gd +++ b/scripts/players.gd @@ -1,27 +1,61 @@ extends Node +class_name Players @export var player_scene: PackedScene = preload("res://objects/player.tscn") +@export var bot_scene: PackedScene = preload("res://objects/bot.tscn") +@export var bot_count: int = 7 +@export var bot_test_mode = false + +@onready var game_state: GameState = get_parent() as GameState signal player_joined(player: Player) signal player_left(player: Player) +static var instance: Players = null + func _ready() -> void: connect("child_entered_tree", on_child_added) + if instance == null: + instance = self + + await get_tree().create_timer(0.5).timeout + + for i in range(bot_count): + create_bot(i) + #bot.player_name = "Bot %d" % i + #bot.player_pronouns = "they/them" @rpc("any_peer", "call_remote", "reliable") -func create_player_for_session_id(session_id: int) -> void: +func clear_all_players(): + for child in get_children(): + child.queue_free() + +@rpc("any_peer", "call_remote", "reliable") +func create_player_for_session_id(session_id: int) -> Player: for child in get_children(): var player: Player = child as Player if player == null: continue if player.session_id == session_id: - return + return player var player: Player = player_scene.instantiate() as Player player.name = "Player %d" % session_id player.session_id = session_id + player.game_state = game_state print("Created player object for session ID %d" % session_id) add_child(player) + return player + +@rpc("any_peer", "call_remote", "reliable") +func create_bot(bot_id: int) -> Bot: + var bot: Bot = bot_scene.instantiate() as Bot + bot.session_id = bot_id + bot.game_state = game_state + bot.player_name = "Bot %d" % bot_id + bot.test_mode = bot_test_mode + add_child(bot) + return bot func find_player_by_session_id(session_id: int) -> Player: for child in get_children(): @@ -40,8 +74,28 @@ func find_player_by_session_id(session_id: int) -> Player: if player.session_id == session_id: return player return null + +func find_player_by_name(name: String) -> Player: + for player in get_players(): + if player.player_name == name: + return player + return null + +func get_players() -> Array[Player]: + var ret: Array[Player] + for child in get_children(): + if child is Player: + ret.append(child as Player) + return ret + +func get_active_players() -> Array[Player]: + return get_players().filter(func(player: Player): return player.playing) func on_child_added(node: Node) -> void: if node is Player: print("Player joined: %d" % node.session_id) player_joined.emit(node as Player) + +func call_on_active_players(method: StringName): + for player in get_active_players(): + player.call(method) diff --git a/scripts/players.gd.uid b/scripts/players.gd.uid new file mode 100644 index 0000000..bcb14e8 --- /dev/null +++ b/scripts/players.gd.uid @@ -0,0 +1 @@ +uid://bge0mj845eubr diff --git a/scripts/prompt.gd b/scripts/prompt.gd new file mode 100644 index 0000000..22e16eb --- /dev/null +++ b/scripts/prompt.gd @@ -0,0 +1,54 @@ +extends Resource +class_name Prompt + +enum PromptType {TEXT, LONG_TEXT, NUMBER, MULTIPLE_CHOICE, COLOUR, PLAYER, CONFIRMATION, SHOW_TEAM, SHOW_ROLE} + +@export_multiline var text: String: + set(val): + text = val + id = text.hash() +@export_multiline var explaination: String +@export var type: PromptType +@export var options: Array[String] +@export var interruptable: bool = false +var id: int = randi() +var context: Dictionary #[String, String] + +static func create(text: String, type: PromptType) -> Prompt: + var prompt: Prompt = Prompt.new() + prompt.text = text + prompt.type = type + return prompt + +func format_text() -> String: + return text.format(context) + +func with_context(additional_context: Dictionary) -> Prompt: + var ret: Prompt = duplicate(true) + ret.context = context.merged(additional_context) + return ret + +func save() -> Dictionary: + return { + "text" = text, + "explaination" = explaination, + "type" = type as int, + "options" = options, + "context" = context, + "interruptable" = interruptable, + "id" = id, + } + +static func load(dict: Dictionary) -> Prompt: + if dict.is_empty(): + return null + var ret: Prompt = Prompt.new() + ret.text = dict.get("text", "") + ret.explaination = dict.get("explaination", "") + ret.type = dict.get("type", 0) as PromptType + ret.options.assign(dict.get("options", [])) + ret.context = dict.get("context", {}) + #ret.context.assign(dict.get("context", {})) + ret.id = dict.get("id", 0) + ret.interruptable = dict.get("interruptable", false) + return ret diff --git a/scripts/prompt.gd.uid b/scripts/prompt.gd.uid new file mode 100644 index 0000000..9c9930d --- /dev/null +++ b/scripts/prompt.gd.uid @@ -0,0 +1 @@ +uid://dqgc4kbjfvg13 diff --git a/scripts/prompt_manager.gd b/scripts/prompt_manager.gd index a1119e2..b77c32a 100644 --- a/scripts/prompt_manager.gd +++ b/scripts/prompt_manager.gd @@ -4,33 +4,33 @@ class_name PromptManager @export var multi_choice_button_scene: PackedScene = preload("res://objects/multi_choice_button.tscn") @export var prompt_text_format: String = "[center]%s[/center]" -enum PromptType {TEXT, LONG_TEXT, NUMBER, MULTIPLE_CHOICE, COLOUR, PLAYER} - -var current_prompt: Dictionary +var current_prompt: Prompt var player: Player: - set(value): - if player != null: - player.disconnect("prompt_changed", display_prompt) - player = value - player.connect("prompt_changed", display_prompt) - display_prompt(player.current_prompt) + set = set_player + +func _ready() -> void: + hide_everything() + +func hide_everything(): + # hide all children + for child in get_children(): + child.visible = false -func display_prompt(prompt: Dictionary): - if prompt.is_empty(): +func display_prompt(prompt: Prompt): + if prompt == null: + print("Displaying no prompt") visible = false return - print("Displaying prompt \"%s\"" % prompt["text"]) + print("Displaying prompt \"%s\"" % prompt.text) current_prompt = prompt visible = true - # hide all children - for child in get_children(): - child.visible = false + hide_everything() - $PromptLabel.text = prompt_text_format % prompt["text"] + $PromptLabel.text = prompt_text_format % prompt.format_text() $PromptLabel.visible = true # clear all prompt buttons @@ -38,33 +38,64 @@ func display_prompt(prompt: Dictionary): $MultichoiceButtons.remove_child(button) button.queue_free() - if prompt["type"] == PromptType.LONG_TEXT: + if prompt.type == Prompt.PromptType.LONG_TEXT: $LongTextEdit.visible = true $LongTextEdit.text = "" $SubmitButton.visible = true - elif prompt["type"] == PromptType.TEXT: + elif prompt.type == Prompt.PromptType.TEXT: $LineEdit.visible = true $LineEdit.text = "" $SubmitButton.visible = true #$LongTextEdit.placeholder_text = prompt.options - elif prompt["type"] == PromptType.MULTIPLE_CHOICE: + elif prompt.type == Prompt.PromptType.MULTIPLE_CHOICE or prompt.type == Prompt.PromptType.PLAYER: $MultichoiceButtons.visible = true for option in prompt.options: var button: Button = multi_choice_button_scene.instantiate() as Button button.text = option $MultichoiceButtons.add_child(button) button.connect("pressed", submit_result.bind(option)) + elif prompt.type == Prompt.PromptType.CONFIRMATION: + $SubmitButton.visible = true + elif prompt.type == Prompt.PromptType.SHOW_TEAM: + $SubmitButton.visible = true + var team: Team = Team.teams.get(prompt.context.get("team")) + if team != null: + $SubmitButton.disabled = true + $TeamCard.connect("revealed", func(): $SubmitButton.disabled = false) + $TeamCard.team = team + $TeamCard.visible = true + $TeamCard.appear() + elif prompt.type == Prompt.PromptType.SHOW_ROLE: + $SubmitButton.visible = true + var role: Role = Role.roles.get(prompt.context.get("role")) + if role != null: + $SubmitButton.disabled = true + $RoleCard.connect("revealed", func(): $SubmitButton.disabled = false) + $RoleCard.role = role + $RoleCard.visible = true + $RoleCard.appear() func submit_button_pressed() -> void: - if current_prompt.is_empty(): + if current_prompt == null: return - match current_prompt["type"] as PromptType: - PromptType.TEXT: + match current_prompt.type as Prompt.PromptType: + Prompt.PromptType.TEXT: submit_result($LineEdit.text) - PromptType.LONG_TEXT: + Prompt.PromptType.LONG_TEXT: submit_result($LongTextEdit.text) + Prompt.PromptType.CONFIRMATION,Prompt.PromptType.SHOW_ROLE,Prompt.PromptType.SHOW_TEAM: + submit_result("confirmed") func submit_result(result: String): - player.submit_prompt_answer.rpc_id(1, result) + var prompt: Prompt = current_prompt visible = false - current_prompt.clear() + current_prompt = null + player.submit_prompt_answer.rpc(prompt.id, result) + + +func set_player(value: Player) -> void: + if player != null: + player.disconnect("prompt_changed", display_prompt) + player = value + player.connect("prompt_changed", display_prompt) + display_prompt(player.current_prompt) diff --git a/scripts/prompt_manager.gd.uid b/scripts/prompt_manager.gd.uid new file mode 100644 index 0000000..acf3f85 --- /dev/null +++ b/scripts/prompt_manager.gd.uid @@ -0,0 +1 @@ +uid://dtlwwcrjtlvr7 diff --git a/scripts/proxy_delegate.gd b/scripts/proxy_delegate.gd index eff6c7c..cf9590a 100644 --- a/scripts/proxy_delegate.gd +++ b/scripts/proxy_delegate.gd @@ -1,4 +1,4 @@ -extends Node +extends Container class_name ProxyDelegate @export var delegate_scene: PackedScene diff --git a/scripts/proxy_delegate.gd.uid b/scripts/proxy_delegate.gd.uid new file mode 100644 index 0000000..24dbece --- /dev/null +++ b/scripts/proxy_delegate.gd.uid @@ -0,0 +1 @@ +uid://maxp7jokvgw6 diff --git a/scripts/util/center-pivot.gd b/scripts/util/center-pivot.gd new file mode 100644 index 0000000..7428c36 --- /dev/null +++ b/scripts/util/center-pivot.gd @@ -0,0 +1,9 @@ +@tool +extends Control + +func _ready() -> void: + connect("resized", _center_pivot) + _center_pivot() + +func _center_pivot() -> void: + pivot_offset = size/2.0 diff --git a/scripts/util/center-pivot.gd.uid b/scripts/util/center-pivot.gd.uid new file mode 100644 index 0000000..5228f11 --- /dev/null +++ b/scripts/util/center-pivot.gd.uid @@ -0,0 +1 @@ +uid://d0t3ym4gwmmx2 diff --git a/scripts/util/multi_await.gd b/scripts/util/multi_await.gd new file mode 100644 index 0000000..ba2ffeb --- /dev/null +++ b/scripts/util/multi_await.gd @@ -0,0 +1,33 @@ +extends RefCounted +class_name MultiAwait + +var waiting_count: int = 0 +var finished: bool = false + +signal done(timed_out: bool) + +func _init(signals: Array[Signal], timeout: float) -> void: + for sig in signals: + var err: int = sig.connect(receive_signal, CONNECT_ONE_SHOT) + if err == Error.OK: + waiting_count += 1 + check_done() + var scene_tree: SceneTree = Engine.get_main_loop() as SceneTree + if scene_tree != null: + scene_tree.create_timer(timeout).timeout.connect(finish.bind(true)) + print("MultiAwait: waiting for %d signals or %f seconds" % [waiting_count,timeout]) + +func receive_signal() -> void: + waiting_count -= 1 + print("MultiAwait: got signal, %d signals left" % [waiting_count]) + check_done() + +func check_done() -> void: + if waiting_count <= 0: + finish(false) + +func finish(timed_out: bool) -> void: + if !finished: + print("MultiAwait: done, timed_out: %s" % [timed_out]) + done.emit(timed_out) + finished = true diff --git a/scripts/util/multi_await.gd.uid b/scripts/util/multi_await.gd.uid new file mode 100644 index 0000000..5c6cf7c --- /dev/null +++ b/scripts/util/multi_await.gd.uid @@ -0,0 +1 @@ +uid://whn2xwps7cqr