Rebrand project and refresh title presentation

This commit is contained in:
Alexander Sellite 2026-08-25 17:14:12 -04:00
parent 17fef2c5d4
commit 7ae20789a9
138 changed files with 1511 additions and 1498 deletions

View file

@ -2,7 +2,7 @@ extends SceneTree
const CHARACTER_SCENE: PackedScene = preload(
"res://art/exported/characters/base/netfishing_base_character.glb"
"res://art/exported/characters/base/straywild_base_character.glb"
)
const EXPECTED_ANIMATIONS: Array[StringName] = [

View file

@ -278,7 +278,7 @@ func _validate_manager(manager: ControllerMappingManagerType) -> String:
func _validate_portmaster_launcher() -> String:
const launcher_path: String = "res://scripts/portmaster/NETfishing.sh"
const launcher_path: String = "res://scripts/portmaster/straywild.sh"
if not FileAccess.file_exists(launcher_path):
return "PortMaster launcher template is missing"
var launcher: String = FileAccess.get_file_as_string(launcher_path)
@ -291,9 +291,9 @@ func _validate_portmaster_launcher() -> String:
"guide:b8,start:b7,back:b6",
"leftstick:b9",
"rightstick:b12",
"netfishing_controllerconfig=\"$GODOT_MUOS_MAPPING\"",
"GPTOKEYB_CONFIG=\"$GAMEDIR/netfishing.gptk\"",
"$GPTOKEYB \"NETfishing.aarch64\" -c \"$GPTOKEYB_CONFIG\" &",
"straywild_controllerconfig=\"$GODOT_MUOS_MAPPING\"",
"GPTOKEYB_CONFIG=\"$GAMEDIR/straywild.gptk\"",
"$GPTOKEYB \"straywild.aarch64\" -c \"$GPTOKEYB_CONFIG\" &",
"pm_platform_helper \"$GAME_EXECUTABLE\"",
"\"$GAME_LAUNCHER\"",
"\"$CONTROLLER_MAPPING_FILE\"",
@ -304,7 +304,7 @@ func _validate_portmaster_launcher() -> String:
if "$'\\n'" in launcher:
return "PortMaster launcher appends mappings across a Weston-unsafe newline"
const game_launcher_path: String = (
"res://scripts/portmaster/launch-netfishing.sh"
"res://scripts/portmaster/launch-straywild.sh"
)
if not FileAccess.file_exists(game_launcher_path):
return "PortMaster game launcher wrapper is missing"

View file

@ -122,8 +122,38 @@ func _validate_primary_menu_navigation() -> void:
_expect(
play_button.icon != null
and play_button.icon.resource_path
== "res://ui/icons/main_menu/continue.png",
"The Play action does not use the original Continue icon.",
== "res://ui/icons/new_menu/play.png"
and play_button.text.is_empty(),
"The Play action is not presented as the large square icon button.",
)
_expect(
is_equal_approx(play_button.size.x, play_button.size.y),
"The Play action is not square.",
)
var online_button := title.get_node("%JoinGameButton") as Button
var settings_button := title.get_node("%SettingsButton") as Button
var credits_button := title.get_node("%CreditsButton") as Button
var close_button := title.get_node("%QuitButton") as Button
for secondary_button: Button in [
online_button,
settings_button,
credits_button,
close_button,
]:
_expect(
is_equal_approx(
secondary_button.size.x,
secondary_button.size.y,
),
"A secondary title action is not square.",
)
_expect(
is_equal_approx(
close_button.position.y + close_button.size.y
- online_button.position.y,
play_button.size.y,
),
"The secondary title-action stack does not match Play's height.",
)
_expect(
not (title.get_node("%NewGameButton") as Control).visible
@ -131,24 +161,29 @@ func _validate_primary_menu_navigation() -> void:
"Legacy New/Delete title bubbles are still visible.",
)
_assert_neighbor(
title.get_node("%JoinGameButton") as Control,
&"focus_neighbor_right",
play_button,
&"focus_neighbor_right",
title.get_node("%JoinGameButton") as Control,
)
_assert_neighbor(
title.get_node("%JoinGameButton") as Control,
&"focus_neighbor_left",
play_button,
)
_assert_neighbor(
title.get_node("%JoinGameButton") as Control,
&"focus_neighbor_bottom",
title.get_node("%SettingsButton") as Control,
)
_assert_neighbor(
title.get_node("%SettingsButton") as Control,
&"focus_neighbor_left",
play_button,
&"focus_neighbor_bottom",
title.get_node("%CreditsButton") as Control,
)
_assert_neighbor(
title.get_node("%CreditsButton") as Control,
&"focus_neighbor_right",
play_button,
)
_assert_neighbor(
&"focus_neighbor_bottom",
title.get_node("%QuitButton") as Control,
&"focus_neighbor_left",
play_button,
)
for title_control: Control in title_controls:
_assert_directionally_reachable(title_control, title_controls)
@ -1196,12 +1231,12 @@ func _validate_profile_voice_navigation() -> void:
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"):
if OS.has_environment("straywild_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"
"straywild_PROFILE_VOICE_CAPTURE"
)) == OK,
"The profile voice-page capture could not be saved.",
)

View file

@ -266,22 +266,22 @@ func _validate_four_by_three_centering() -> void:
func _validate_low_end_profile_contract() -> void:
var launcher: String = FileAccess.get_file_as_string(
"res://scripts/portmaster/NETfishing.sh"
"res://scripts/portmaster/straywild.sh"
)
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE:-"))
assert(launcher.contains("straywild_PERFORMANCE_PROFILE:-"))
assert(launcher.contains("$CONFDIR/performance_profile"))
assert(launcher.contains("normal)"))
assert(launcher.contains("light|\"\")"))
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE=normal"))
assert(launcher.contains("NETFISHING_PERFORMANCE_PROFILE=light"))
assert(launcher.contains("NETFISHING_LOW_END=1"))
assert(launcher.contains("straywild_PERFORMANCE_PROFILE=normal"))
assert(launcher.contains("straywild_PERFORMANCE_PROFILE=light"))
assert(launcher.contains("straywild_LOW_END=1"))
assert(launcher.contains("--max-fps 30"))
assert(launcher.contains("--audio-output-latency 40"))
var builder: String = FileAccess.get_file_as_string(
"res://scripts/build_portmaster.sh"
)
assert(builder.contains("prepare_portmaster_assets.sh"))
assert(builder.contains("netfishing-portmaster-export"))
assert(builder.contains("straywild-portmaster-export"))
var asset_profile: String = FileAccess.get_file_as_string(
"res://scripts/prepare_portmaster_assets.sh"
)

View file

@ -15,7 +15,7 @@ func _initialize() -> void:
func _run() -> void:
var defaults := ConfigType.new()
defaults.set("data_directory", "/tmp/netfishing-server")
defaults.set("data_directory", "/tmp/straywild-server")
defaults.call("_validate")
assert(defaults.is_valid())
assert(not bool(defaults.get("public_listing")))
@ -37,7 +37,7 @@ func _run() -> void:
file.set_value("world", "seed", 928374)
file.set_value("server", "public", true)
file.set_value("server", "data_directory", "/tmp/configured-server")
file.set_value("discovery", "url", "https://discovery.netfishing.org/")
file.set_value("discovery", "url", "https://discovery.straywild.io/")
file.set_value("privacy", "chat_logging", true)
file.set_value(
"privacy",
@ -59,7 +59,7 @@ func _run() -> void:
assert(int(configured.get("max_players")) == 12)
assert(int(configured.get("world_seed")) == 928374)
assert(bool(configured.get("public_listing")))
assert(str(configured.get("discovery_url")) == "https://discovery.netfishing.org")
assert(str(configured.get("discovery_url")) == "https://discovery.straywild.io")
assert(bool(configured.get("chat_logging")))
assert(
str(configured.get("chat_log_path"))

View file

@ -197,7 +197,7 @@ func _run() -> void:
var invalid_state: Dictionary = valid_state.duplicate(true)
invalid_state["display_scale"] = 1000.0
assert(not NetworkFishShowcaseProtocol.validate_state(invalid_state))
assert(NetworkProtocol.PROTOCOL_VERSION == 10)
assert(NetworkProtocol.PROTOCOL_VERSION == 11)
assert(NetworkProtocol.ENET_CHANNEL_COUNT == 17)
assert(
NetworkProtocol.FISH_QUALITY_CAPABILITY

View file

@ -26,7 +26,7 @@ func _run() -> void:
_validate_collection_mastery()
_validate_version_four_migration()
_validate_fishing_protocol_v2()
assert(NetworkProtocol.PROTOCOL_VERSION == 10)
assert(NetworkProtocol.PROTOCOL_VERSION == 11)
assert(NetworkProtocol.ENET_CHANNEL_COUNT == 17)
assert(NetworkProtocol.MOVEMENT_ANIMATION_CHANNEL == 11)
assert(

View file

@ -666,7 +666,7 @@ func _to_screen_rect(
func _capture_inventory_pages(player_menu: PlayerMenu) -> void:
if not OS.has_environment("NETFISHING_NOTEPAD_CAPTURE"):
if not OS.has_environment("straywild_NOTEPAD_CAPTURE"):
return
player_menu.visible = true
var sections: Array[PlayerMenu.Section] = [
@ -700,7 +700,7 @@ func _capture_inventory_pages(player_menu: PlayerMenu) -> void:
func _save_capture(suffix: String) -> void:
var image: Image = root.get_texture().get_image()
var path: String = "%s-%s.png" % [
OS.get_environment("NETFISHING_NOTEPAD_CAPTURE"),
OS.get_environment("straywild_NOTEPAD_CAPTURE"),
suffix,
]
assert(image.save_png(path) == OK)

View file

@ -123,7 +123,6 @@ func _validate_main_profile(main: Node) -> void:
var game_ui := main.get_node("%GameUI") as GameUI
var title_screen := game_ui.get_title_screen()
assert(title_screen != null)
assert(not title_screen.is_decorative_presentation_active())
var player_menu := game_ui.get("_player_menu") as PlayerMenu
assert(player_menu != null)
assert(not player_menu.is_cooler_water_effect_enabled())
@ -159,8 +158,6 @@ func _validate_normal_profile(main: Node) -> void:
var game_ui := main.get_node("%GameUI") as GameUI
var title_screen := game_ui.get_title_screen()
assert(title_screen != null)
assert(title_screen.is_decorative_presentation_active())
assert(title_screen.is_decorative_bubble_scheduler_active())
var player_menu := game_ui.get("_player_menu") as PlayerMenu
assert(player_menu != null)
assert(player_menu.is_cooler_water_effect_enabled())

View file

@ -201,13 +201,13 @@ func _add_test_catch(player: Player, fish: FishData) -> void:
func _capture_if_requested(suffix: String) -> void:
if not OS.has_environment("NETFISHING_LOGBOOK_CAPTURE"):
if not OS.has_environment("straywild_LOGBOOK_CAPTURE"):
return
await process_frame
await process_frame
var image: Image = root.get_texture().get_image()
var path: String = (
OS.get_environment("NETFISHING_LOGBOOK_CAPTURE")
OS.get_environment("straywild_LOGBOOK_CAPTURE")
+ suffix
+ ".png"
)

View file

@ -23,11 +23,11 @@ func _initialize() -> void:
func _run() -> void:
if OS.has_environment("NETFISHING_TEST_CREATE_ROOT"):
if OS.has_environment("straywild_TEST_CREATE_ROOT"):
var data_root := PlayerDataRoot.new()
root.add_child(data_root)
var result: Dictionary = data_root.create_unbound_root(
OS.get_environment("NETFISHING_TEST_CREATE_ROOT")
OS.get_environment("straywild_TEST_CREATE_ROOT")
)
assert(bool(result.get("ok", false)))
data_root.queue_free()

View file

@ -4,7 +4,7 @@
[ext_resource type="Script" path="res://world/generation/terrain_chunk_generator.gd" id="2_generator"]
[ext_resource type="Resource" path="res://world/generation/chunks/terrain_chunk_catalog.tres" id="3_catalog"]
[ext_resource type="PackedScene" path="res://player/player.tscn" id="4_player"]
[ext_resource type="Environment" path="res://world/environment/netfishing_environment.tres" id="5_environment"]
[ext_resource type="Environment" path="res://world/environment/straywild_environment.tres" id="5_environment"]
[node name="TerrainChunkGeneratorTest" type="Node3D"]
script = ExtResource("1_test")

View file

@ -21,6 +21,10 @@ func _run() -> void:
var credits_button := title_screen.get_node(
"%CreditsButton"
) as BubbleButton
var play_button := title_screen.get_node("%PlayButton") as BubbleButton
var continue_stats_drawer := title_screen.get_node(
"%ContinueStatsDrawer"
) as RichTextLabel
var credits_page := title_screen.get_node(
"%CreditsPage"
) as TitleCreditsPageType
@ -34,9 +38,32 @@ func _run() -> void:
await process_frame
_expect(credits_button != null, "title menu exposes a credits button")
_expect(play_button != null, "title menu exposes the play button")
_expect(
continue_stats_drawer != null,
"play button owns a dedicated save-preview drawer",
)
if play_button != null and continue_stats_drawer != null:
_expect(
continue_stats_drawer.get_parent() == play_button,
"save preview extends directly from the play button",
)
_expect(
continue_stats_drawer.position.y < play_button.size.y
and (
continue_stats_drawer.position.y
+ continue_stats_drawer.size.y
) > play_button.size.y,
"save preview overlaps the play edge and extends below it",
)
_expect(
continue_stats_drawer.mouse_filter
== Control.MOUSE_FILTER_IGNORE,
"save preview drawer cannot intercept menu input",
)
_expect(
credits_button.icon != null and credits_button.text.is_empty(),
"credits bubble uses its authored icon",
"credits action uses its icon in the square-button presentation",
)
_expect(credits_page != null, "title screen contains the credits page")
_expect(not credits_page.visible, "credits page starts closed")
@ -44,29 +71,39 @@ func _run() -> void:
Rect2(Vector2.ZERO, bubble_field.size).encloses(
Rect2(credits_button.position, credits_button.size)
),
"credits bubble stays inside the authored title field",
"credits button stays inside the authored title field",
)
_expect(
credits_button.mouse_filter == Control.MOUSE_FILTER_STOP,
"credits bubble accepts pointer input",
"credits button accepts pointer input",
)
if OS.has_environment("NETFISHING_TITLE_MENU_CAPTURE"):
if OS.has_environment("straywild_TITLE_MENU_CAPTURE"):
(title_screen.get_node("%StartPromptCenter") as Control).hide()
title_screen.set_process(true)
await create_timer(0.5).timeout
_expect(
_save_capture(
OS.get_environment("NETFISHING_TITLE_MENU_CAPTURE")
OS.get_environment("straywild_TITLE_MENU_CAPTURE")
) == OK,
"title menu validation capture saves successfully",
)
title_screen.set_process(false)
title_screen.set("_navigation_focus_active", false)
credits_button.call("_set_hovered", true)
credits_button.advance_emphasis(1.0)
_expect(
(credits_button.get_node("HoverDrawer") as Control).visible,
"pointer hover reveals the credits drawer before activation",
)
credits_button.pressed.emit()
await process_frame
_expect(credits_page.visible, "pointer activation opens credits")
_expect(not presentation.visible, "credits replace the primary title menu")
_expect(
not (credits_button.get_node("HoverDrawer") as Control).visible,
"opening a title page collapses its hover drawer",
)
_expect(
root.gui_get_focus_owner() != back_button,
"pointer activation does not pseudo-select back",
@ -80,11 +117,11 @@ func _run() -> void:
back_button.mouse_filter == Control.MOUSE_FILTER_STOP,
"credits back button accepts pointer clicks",
)
if OS.has_environment("NETFISHING_CREDITS_CAPTURE"):
if OS.has_environment("straywild_CREDITS_CAPTURE"):
await process_frame
_expect(
_save_capture(
OS.get_environment("NETFISHING_CREDITS_CAPTURE")
OS.get_environment("straywild_CREDITS_CAPTURE")
) == OK,
"credits validation capture saves successfully",
)
@ -97,6 +134,30 @@ func _run() -> void:
"pointer return leaves the title menu unfocused",
)
var online_button := title_screen.get_node(
"%JoinGameButton"
) as BubbleButton
var join_game_page := title_screen.get_node("%JoinGamePage") as Control
online_button.call("_set_hovered", true)
online_button.advance_emphasis(1.0)
_expect(
(online_button.get_node("HoverDrawer") as Control).visible,
"pointer hover reveals the online drawer before activation",
)
online_button.pressed.emit()
await process_frame
_expect(join_game_page.visible, "online activation opens the join page")
_expect(
not (online_button.get_node("HoverDrawer") as Control).visible,
"opening the join page collapses the online drawer",
)
title_screen.call("_close_join_game")
await process_frame
_expect(
not (online_button.get_node("HoverDrawer") as Control).visible,
"returning from the join page does not restore stale pointer hover",
)
title_screen.set("_navigation_focus_active", true)
credits_button.grab_focus()
credits_button.pressed.emit()
@ -134,7 +195,7 @@ func _run() -> void:
_expect(not credits_page.visible, "ui cancel closes credits")
_expect(
root.gui_get_focus_owner() == credits_button,
"navigation return restores focus to the credits bubble",
"navigation return restores focus to the credits button",
)
var chillnfill_name := credits_page.get_node(

View file

@ -66,12 +66,6 @@ func _run() -> void:
var pause_profile_stage := pause_menu.get_node(
"ResponsivePauseStage"
) as Control
var decorative_fish_layer := title_screen.get_node(
"DecorativeFishLayer"
) as Control
var decorative_bubble_layer := title_screen.get_node(
"DecorativeBubbleLayer"
) as Control
ui_viewport.add_child(game_ui)
presenter.add_child(ui_viewport)
root.add_child(presenter)
@ -165,26 +159,6 @@ func _run() -> void:
assert(pause_profile_stage.position.is_equal_approx(
expected_profile_position
))
assert(decorative_fish_layer.size.is_equal_approx(
expected_visible_size
))
assert(decorative_bubble_layer.size.is_equal_approx(
expected_visible_size
))
var left_to_right_bounds: Vector2 = (
TitleScreen.get_decorative_fish_crossing_bounds(
expected_visible_size.x, 160.0, 1.0
)
)
var right_to_left_bounds: Vector2 = (
TitleScreen.get_decorative_fish_crossing_bounds(
expected_visible_size.x, 160.0, -1.0
)
)
assert(left_to_right_bounds.x < -160.0)
assert(left_to_right_bounds.y > expected_visible_size.x)
assert(right_to_left_bounds.x > expected_visible_size.x)
assert(right_to_left_bounds.y < -160.0)
assert(is_equal_approx(presenter.scale.x, presenter.scale.y))
assert(is_equal_approx(ui_root.scale.x, ui_root.scale.y))
var effective_scale: float = presenter.scale.x * ui_root.scale.x
@ -310,13 +284,13 @@ func _run() -> void:
chat_panel.position.x * effective_scale,
]
)
if OS.has_environment("NETFISHING_UI_SCALE_CAPTURE"):
if OS.has_environment("straywild_UI_SCALE_CAPTURE"):
await process_frame
var capture: Image = root.get_texture().get_image()
var capture_path: String = (
"%s-requested-%dx%d-actual-%dx%d.png"
) % [
OS.get_environment("NETFISHING_UI_SCALE_CAPTURE"),
OS.get_environment("straywild_UI_SCALE_CAPTURE"),
target_size.x,
target_size.y,
actual_size.x,

View file

@ -16,7 +16,7 @@ const CalendarSeasonType = preload("res://world/calendar_season.gd")
func _initialize() -> void:
assert(NetworkProtocol.PROTOCOL_VERSION == 10)
assert(NetworkProtocol.PROTOCOL_VERSION == 11)
assert(
NetworkWorldSpawnProtocol.CAPABILITY
== NetworkProtocol.WORLD_SPAWN_CAPABILITY

View file

@ -304,7 +304,7 @@ func _validate_environment_presentation() -> void:
var sky := Sky.new()
var sky_material := ShaderMaterial.new()
sky_material.shader = preload(
"res://world/environment/netfishing_sky.gdshader"
"res://world/environment/straywild_sky.gdshader"
)
sky.sky_material = sky_material
environment.sky = sky
@ -352,7 +352,7 @@ func _validate_environment_presentation() -> void:
"res://world/materials/stylized_water.gdshader"
)
var sky_shader: Shader = preload(
"res://world/environment/netfishing_sky.gdshader"
"res://world/environment/straywild_sky.gdshader"
)
assert("uniform float fog_horizon_occlusion" in sky_shader.code)
assert("fog_horizon_color.rgb" in sky_shader.code)

View file

@ -283,7 +283,7 @@ func _validate_weather_presentation() -> void:
var sky := Sky.new()
var sky_material := ShaderMaterial.new()
sky_material.shader = preload(
"res://world/environment/netfishing_sky.gdshader"
"res://world/environment/straywild_sky.gdshader"
)
sky.sky_material = sky_material
environment.sky = sky