forked from woofmeow/straywild
feat: add selectable animalese voice sets
This commit is contained in:
parent
364e7dc282
commit
ce733818e2
247 changed files with 2675 additions and 302 deletions
|
|
@ -13,6 +13,9 @@ const TitleConfirmationScene = preload(
|
|||
const MailPageType = preload("res://ui/mail_page.gd")
|
||||
const LogbookPageType = preload("res://ui/logbook_page.gd")
|
||||
const ProfilePageType = preload("res://ui/profile_page.gd")
|
||||
const VoiceProfilesType = preload(
|
||||
"res://player/animalese_voice_profiles.gd"
|
||||
)
|
||||
const PlayerMenuScene = preload("res://ui/player_menu.tscn")
|
||||
const PlayerMenuType = preload("res://ui/player_menu.gd")
|
||||
const BagItemSpriteScene = preload(
|
||||
|
|
@ -42,6 +45,7 @@ func _run() -> void:
|
|||
await _validate_data_settings_navigation()
|
||||
await _validate_mail_navigation()
|
||||
await _validate_profile_confirmation_focus()
|
||||
await _validate_profile_voice_navigation()
|
||||
await _validate_inventory_tab_zone_transitions()
|
||||
await _validate_player_menu_nested_controller_back()
|
||||
await _validate_confirmation_dialog_navigation()
|
||||
|
|
@ -354,6 +358,138 @@ func _validate_profile_confirmation_focus() -> void:
|
|||
await process_frame
|
||||
|
||||
|
||||
func _validate_profile_voice_navigation() -> void:
|
||||
var page := ProfilePageType.new() as Control
|
||||
page.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
root.add_child(page)
|
||||
await process_frame
|
||||
page.call("activate")
|
||||
page.call("set_interactive", true)
|
||||
page.call("_select_category", "voice")
|
||||
await process_frame
|
||||
page.set(
|
||||
"_controller_zone",
|
||||
ProfilePageType.ControllerZone.OPTIONS,
|
||||
)
|
||||
page.set("_controller_option_depth", 0)
|
||||
page.call("_apply_controller_zone_focus")
|
||||
page.call("_focus_controller_zone")
|
||||
await process_frame
|
||||
var sample_grid := page.find_child(
|
||||
"VoiceSampleSetGrid", true, false
|
||||
) as GridContainer
|
||||
var pitch_grid := page.find_child(
|
||||
"VoicePitchGrid", true, false
|
||||
) as GridContainer
|
||||
var speed_grid := page.find_child(
|
||||
"VoiceSpeedGrid", true, false
|
||||
) as GridContainer
|
||||
var call_grid := page.find_child(
|
||||
"VoiceCallGrid", true, false
|
||||
) as GridContainer
|
||||
_expect(
|
||||
is_instance_valid(sample_grid)
|
||||
and is_instance_valid(pitch_grid)
|
||||
and is_instance_valid(speed_grid)
|
||||
and is_instance_valid(call_grid),
|
||||
"The voice page is missing a settings section.",
|
||||
)
|
||||
if (
|
||||
not is_instance_valid(sample_grid)
|
||||
or not is_instance_valid(pitch_grid)
|
||||
or not is_instance_valid(speed_grid)
|
||||
or not is_instance_valid(call_grid)
|
||||
):
|
||||
page.queue_free()
|
||||
await process_frame
|
||||
return
|
||||
var sample_buttons: Array[Control] = []
|
||||
for item: Variant in page.call("_controls_under", sample_grid):
|
||||
sample_buttons.append(item as Control)
|
||||
_expect(
|
||||
sample_buttons.size() == 3,
|
||||
"The voice-set row must expose kat, robot, and kim.",
|
||||
)
|
||||
if sample_buttons.size() != 3:
|
||||
page.queue_free()
|
||||
await process_frame
|
||||
return
|
||||
var kat_button := sample_grid.get_node("VoiceSet_kat") as Button
|
||||
var robot_button := sample_grid.get_node("VoiceSet_robot") as Button
|
||||
var kim_button := sample_grid.get_node("VoiceSet_kim") as Button
|
||||
_expect(kat_button.text == "kat", "The default voice set is not labeled kat.")
|
||||
_expect(robot_button.text == "robot", "The tone voice set is not labeled robot.")
|
||||
_expect(kim_button.text == "kim", "The kim voice set is not labeled kim.")
|
||||
_expect(kat_button.button_pressed, "The kat voice set is not selected by default.")
|
||||
var option_controls: Array[Control] = []
|
||||
var option_groups: Array = page.call("_controller_option_groups")
|
||||
for item: Variant in option_groups[0]:
|
||||
option_controls.append(item as Control)
|
||||
_expect(
|
||||
option_controls.size()
|
||||
== (
|
||||
VoiceProfilesType.SAMPLE_SET_OPTIONS.size()
|
||||
+ VoiceProfilesType.OPTIONS.size()
|
||||
+ VoiceProfilesType.SPEED_OPTIONS.size()
|
||||
+ VoiceProfilesType.CALL_OPTIONS.size()
|
||||
),
|
||||
"The controller voice zone does not contain every voice setting.",
|
||||
)
|
||||
_assert_directionally_reachable(kat_button, option_controls)
|
||||
var kat_down := kat_button.get_node_or_null(
|
||||
kat_button.focus_neighbor_bottom
|
||||
) as Control
|
||||
_expect(
|
||||
kat_down != null and pitch_grid.is_ancestor_of(kat_down),
|
||||
"Down from the voice-set row does not enter the pitch row.",
|
||||
)
|
||||
if OS.has_environment("NETFISHING_PROFILE_VOICE_CAPTURE"):
|
||||
await RenderingServer.frame_post_draw
|
||||
var capture := root.get_viewport().get_texture().get_image()
|
||||
_expect(
|
||||
capture.save_png(OS.get_environment(
|
||||
"NETFISHING_PROFILE_VOICE_CAPTURE"
|
||||
)) == OK,
|
||||
"The profile voice-page capture could not be saved.",
|
||||
)
|
||||
robot_button.grab_focus()
|
||||
robot_button.button_pressed = true
|
||||
robot_button.pressed.emit()
|
||||
await process_frame
|
||||
_expect(
|
||||
root.gui_get_focus_owner() == robot_button,
|
||||
"Selecting robot moved controller focus out of the voice-set row.",
|
||||
)
|
||||
_expect(
|
||||
str(page.get("_draft_sample_set_id")) == "robot",
|
||||
"Selecting robot did not update the profile draft.",
|
||||
)
|
||||
kim_button.grab_focus()
|
||||
kim_button.button_pressed = true
|
||||
kim_button.pressed.emit()
|
||||
await process_frame
|
||||
_expect(
|
||||
root.gui_get_focus_owner() == kim_button,
|
||||
"Selecting kim moved controller focus out of the voice-set row.",
|
||||
)
|
||||
_expect(
|
||||
str(page.get("_draft_sample_set_id")) == "kim",
|
||||
"Selecting kim did not update the profile draft.",
|
||||
)
|
||||
var category_controls: Array[Control] = []
|
||||
for item: Variant in page.call(
|
||||
"_controls_under", page.get("_category_list")
|
||||
):
|
||||
category_controls.append(item as Control)
|
||||
for category_control: Control in category_controls:
|
||||
_expect(
|
||||
category_control.focus_mode == Control.FOCUS_NONE,
|
||||
"The voice options zone leaked focus into profile categories.",
|
||||
)
|
||||
page.queue_free()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _validate_player_menu_nested_controller_back() -> void:
|
||||
var menu := PlayerMenuScene.instantiate() as Control
|
||||
root.add_child(menu)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ func _run_host() -> void:
|
|||
for _frame: int in 4:
|
||||
await physics_frame
|
||||
assert(session.set_host_open(true))
|
||||
var chat_service := main.get_node(
|
||||
"%NetworkChatService"
|
||||
) as NetworkChatService
|
||||
var voice_messages: Array[Dictionary] = []
|
||||
chat_service.message_received.connect(func(message: Dictionary) -> void:
|
||||
if str(message.get("body", "")) == "voice profile sync":
|
||||
voice_messages.append(message)
|
||||
)
|
||||
var remote_peer_id: int = await _wait_for_remote_peer(session)
|
||||
assert(remote_peer_id > 1)
|
||||
var record := session.get_peer_record(remote_peer_id)
|
||||
|
|
@ -50,6 +58,15 @@ func _run_host() -> void:
|
|||
assert(avatar != null)
|
||||
assert(avatar.appearance_snapshot == changed)
|
||||
assert(record.display_name != "NetworkProfileService")
|
||||
var voice_message_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < voice_message_deadline
|
||||
and voice_messages.is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(not voice_messages.is_empty())
|
||||
assert(str(voice_messages[0].get("voice_id", "")) == "deep")
|
||||
assert(str(voice_messages[0].get("sample_set_id", "")) == "kim")
|
||||
var disconnect_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < disconnect_deadline
|
||||
|
|
@ -95,9 +112,10 @@ func _run_client() -> void:
|
|||
service.get_persisted_name(),
|
||||
changed,
|
||||
true,
|
||||
service.get_persisted_voice_id(),
|
||||
"deep",
|
||||
service.get_persisted_speech_speed_id(),
|
||||
service.get_persisted_call_id(),
|
||||
"kim",
|
||||
))
|
||||
var apply_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while Time.get_ticks_msec() < apply_deadline and apply_results.is_empty():
|
||||
|
|
@ -105,8 +123,35 @@ func _run_client() -> void:
|
|||
assert(not apply_results.is_empty())
|
||||
assert(bool(apply_results[0][0]))
|
||||
assert(service.get_persisted_appearance() == changed)
|
||||
assert(service.get_persisted_voice_id() == "deep")
|
||||
assert(service.get_persisted_sample_set_id() == "kim")
|
||||
assert(Dictionary(session.get("_local_appearance_snapshot")) == changed)
|
||||
await create_timer(0.75).timeout
|
||||
var player := main.get_node("%PlayerSpawnService").get_local_player() as Player
|
||||
assert(player.get_animalese_voice_id() == "deep")
|
||||
assert(player.get_animalese_sample_set_id() == "kim")
|
||||
var chat_service := main.get_node(
|
||||
"%NetworkChatService"
|
||||
) as NetworkChatService
|
||||
var local_confirmations: Array[Dictionary] = []
|
||||
chat_service.local_message_confirmed.connect(
|
||||
func(message: Dictionary) -> void:
|
||||
if str(message.get("body", "")) == "voice profile sync":
|
||||
local_confirmations.append(message)
|
||||
)
|
||||
assert(chat_service.send_local_message(
|
||||
"voice profile sync",
|
||||
service.get_persisted_voice_id(),
|
||||
service.get_persisted_sample_set_id(),
|
||||
))
|
||||
var confirmation_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < confirmation_deadline
|
||||
and local_confirmations.is_empty()
|
||||
):
|
||||
await process_frame
|
||||
assert(not local_confirmations.is_empty())
|
||||
assert(str(local_confirmations[0].get("voice_id", "")) == "deep")
|
||||
assert(str(local_confirmations[0].get("sample_set_id", "")) == "kim")
|
||||
print("Profile multiplayer client validation: PASS")
|
||||
await _session_cleanup(main, session)
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ func _run() -> void:
|
|||
var creative_credits := credits_page.get_node(
|
||||
"Paper/Margin/Layout/Columns/CreativeCredits"
|
||||
) as VBoxContainer
|
||||
var audio_credits := credits_page.get_node(
|
||||
"Paper/Margin/Layout/Columns/AdditionalCredits/AudioCredits"
|
||||
) as Label
|
||||
_expect(voyager_name.text == "Voyager", "in-game credits use Voyager")
|
||||
_expect(
|
||||
endeavour_name.text == "Endeavour",
|
||||
|
|
@ -175,6 +178,14 @@ func _run() -> void:
|
|||
"shop icon" in tekgator_credit.text.to_lower(),
|
||||
"in-game credits describe Tekgator's shop icon artwork",
|
||||
)
|
||||
_expect(
|
||||
"kat • animalese voice sample" in audio_credits.text,
|
||||
"in-game credits name kat's animalese voice contribution",
|
||||
)
|
||||
_expect(
|
||||
"kim • animalese voice sample" in audio_credits.text,
|
||||
"in-game credits name kim's animalese voice contribution",
|
||||
)
|
||||
_expect(
|
||||
Rect2(Vector2.ZERO, creative_credits.size).encloses(
|
||||
Rect2(tekgator_credit.position, tekgator_credit.size)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue