diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 8406c0a..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,48 +0,0 @@ -# Contributing - -NETfishing is currently developed through focused changes on the repository's -active development branch. Coordinate scope with the project owner before -starting substantial work. - -## Change discipline - -- Keep a change focused; avoid unrelated cleanup. -- Inspect the working tree before editing and preserve existing work. -- Do not change protocol, save, settings, identity, or portable-data versions - as release-label housekeeping. -- Treat the host as authoritative for catches, purchases, sales, jobs, mail, - and other shared state. -- Keep presentation-only systems out of save files and network messages. -- Store runtime assets under repository-owned paths; never reference a - workstation sync or temporary directory. -- Record the source and license of newly imported assets. -- Do not commit `.godot/`, test data, logs, captures, or build outputs. - -## Before requesting review - -```sh -git diff --check -scripts/run_validations.sh quick -git status --short -``` - -Choose additional focused tests from [`docs/TESTING.md`](docs/TESTING.md). -Changes involving networking should run the network suite and a real -two-process check. Visual changes still require graphical review; headless -tests are supporting evidence, not a replacement. - -## Commits - -- Stage audited paths explicitly. -- Use a concise imperative subject that describes the outcome. -- Do not mix generated build artifacts with source changes. -- Do not rewrite published release tags. -- Describe behavior, compatibility impact, validation, and asset provenance in - the review or release record. - -## Style - -Follow the conventions already present in the surrounding GDScript, scene, and -resource files. Prefer typed values, named constants, shared resources, and -small domain-specific services. Avoid duplicating protocol definitions or -using display strings as persistent identifiers. diff --git a/CREDITS.md b/CREDITS.md deleted file mode 100644 index 8edbd4f..0000000 --- a/CREDITS.md +++ /dev/null @@ -1,50 +0,0 @@ -# Credits - -## Project direction - -NETfishing is designed, directed, reviewed, and released by its project -creator. A public-facing creator or studio credit has not yet been recorded in -this repository. - -## Development assistance - -Development has used automated coding assistance for implementation, -investigation, testing, documentation, and review. Design choices, supplied -artwork, acceptance decisions, repository operations, and releases remain -human-controlled. - -This disclosure is intentionally about process. Commit style, code style, or -repository metadata cannot reliably prove whether a particular change was -written with or without assistance. - -## Fonts - -- Tuffy: Thatcher Ulrich, Karoly Barta, and Michael Evans. The bundled license - dedicates the work to the public domain; see `ui/fonts/Tuffy-LICENSE.txt`. -- Seattle Avenue: bundled as `ui/fonts/seattle_avenue.otf`. Author and - redistribution terms still need to be recorded before public distribution. - -## Music - -- `audio/music/title/as_in_four_wolves.ogg`: original title/ambient music by - the project owner. - -## Sound effects - -- “Spinning reel.wav” by tosha73, used as the source for the fishing fight and - manual-reeling loops. Freesound sound 509902, Creative Commons Zero (CC0): - https://freesound.org/s/509902/ -- “Gentle Ocean Waves Loop” by kkenny101, used for the saltwater shoreline - ambience. Freesound sound 852826, Creative Commons Zero (CC0): - https://freesound.org/s/852826/ -- “Quick Water Droplet” by qubodup, used for the bobber water-impact sound. - Freesound sound 792931, Creative Commons Zero (CC0): - https://freesound.org/s/792931/ - -## Artwork - -- 2D artwork: Rheannon Eisworth, contributor. -- 3D models: original work by the project owner. - -Asset categories and release-record requirements are listed in -[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md). diff --git a/README.md b/README.md deleted file mode 100644 index af29cbc..0000000 --- a/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# NETfishing - -NETfishing is a multiplayer-first fishing game built with Godot 4.7. The -current pre-alpha includes host-authoritative fishing and economy flows, -freshwater and saltwater habitats, persistent player data, social features, -customization, jobs, and a controller-aware interface. - -The project is under active development. Interfaces, balance, content, and -save migrations may continue to change before a stable release. - -## Requirements - -- Godot 4.7.x with the GL Compatibility renderer -- Linux, Windows, or an Android development environment supported by Godot -- Bash for the repository helper scripts - -Open `project.godot` in Godot, or start the editor from the repository root: - -```sh -godot --editor --path . -``` - -Run the game directly with: - -```sh -godot --path . -``` - -## Validation - -The validation scripts isolate Godot's settings and application-data roots. -Run the fast, deterministic suite before submitting a change: - -```sh -scripts/run_validations.sh quick -``` - -Additional suites and individual commands are documented in -[`docs/TESTING.md`](docs/TESTING.md). - -## Building - -Export presets are maintained for Linux, Windows, and Android. Repository -scripts expect the matching Godot export templates and platform toolchains to -already be installed: - -```sh -scripts/build_playtest.sh -scripts/build_android_debug.sh -``` - -Build outputs belong under the ignored `builds/` directory. Release builds -must follow the project's separate tagged-release checklist; these convenience -scripts do not create or publish tags. - -## Project map - -- `main/`: composition root and application orchestration -- `world/`: map, environment, water, and world presentation -- `player/`, `fishing/`, `fish/`: player and fishing domain -- `network/`: transport, identity, and host-authoritative services -- `inventory/`, `items/`, `economy/`, `progression/`, `jobs/`: game state -- `save/`, `settings/`: versioned persistence -- `ui/`: gameplay and menu presentation -- `tests/`: focused Godot validation scripts -- `scripts/`: build, bake, and validation entry points - -See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and -[`world/README-WORLD-AUTHORING.md`](world/README-WORLD-AUTHORING.md) for more -detail. - -## Authorship and assets - -NETfishing is human-directed and uses a mixture of human-authored assets and -software-development assistance. The project records this plainly rather than -claiming that repository history can prove how each line was produced. See -[`CREDITS.md`](CREDITS.md) and -[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md). - -No project-wide source license has been selected yet. Do not assume permission -to redistribute the source or bundled assets beyond rights stated in their -individual license records. diff --git a/art/exported/environment/textures/grass_lite.png.import b/art/exported/environment/textures/grass_lite.png.import index a878153..a5ec41c 100644 --- a/art/exported/environment/textures/grass_lite.png.import +++ b/art/exported/environment/textures/grass_lite.png.import @@ -4,16 +4,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://crci2on30ctoc" path.s3tc="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex" -path.etc2="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.etc2.ctex" metadata={ -"imported_formats": ["s3tc_bptc", "etc2_astc"], +"imported_formats": ["s3tc_bptc"], "vram_texture": true } [deps] source_file="res://art/exported/environment/textures/grass_lite.png" -dest_files=["res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex", "res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.etc2.ctex"] +dest_files=["res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex"] [params] diff --git a/art/exported/environment/textures/grass_olive_tile.png.import b/art/exported/environment/textures/grass_olive_tile.png.import index c880374..bd6ee69 100644 --- a/art/exported/environment/textures/grass_olive_tile.png.import +++ b/art/exported/environment/textures/grass_olive_tile.png.import @@ -4,16 +4,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://btxhq3rdlum2" path.s3tc="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex" -path.etc2="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.etc2.ctex" metadata={ -"imported_formats": ["s3tc_bptc", "etc2_astc"], +"imported_formats": ["s3tc_bptc"], "vram_texture": true } [deps] source_file="res://art/exported/environment/textures/grass_olive_tile.png" -dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex", "res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.etc2.ctex"] +dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"] [params] diff --git a/art/exported/environment/textures/sand.png.import b/art/exported/environment/textures/sand.png.import index fdf8720..82f5791 100644 --- a/art/exported/environment/textures/sand.png.import +++ b/art/exported/environment/textures/sand.png.import @@ -4,16 +4,15 @@ importer="texture" type="CompressedTexture2D" uid="uid://bnje415gq85nn" path.s3tc="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex" -path.etc2="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.etc2.ctex" metadata={ -"imported_formats": ["s3tc_bptc", "etc2_astc"], +"imported_formats": ["s3tc_bptc"], "vram_texture": true } [deps] source_file="res://art/exported/environment/textures/sand.png" -dest_files=["res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex", "res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.etc2.ctex"] +dest_files=["res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex"] [params] diff --git a/audio/ambience/waves.wav b/audio/ambience/waves.wav deleted file mode 100644 index 15f258e..0000000 Binary files a/audio/ambience/waves.wav and /dev/null differ diff --git a/audio/ambience/waves.wav.import b/audio/ambience/waves.wav.import deleted file mode 100644 index 5ff6ba8..0000000 --- a/audio/ambience/waves.wav.import +++ /dev/null @@ -1,24 +0,0 @@ -[remap] - -importer="wav" -type="AudioStreamWAV" -uid="uid://dck3tf8qkadea" -path="res://.godot/imported/waves.wav-90ffb886ce064ba838eebb25ec72a17e.sample" - -[deps] - -source_file="res://audio/ambience/waves.wav" -dest_files=["res://.godot/imported/waves.wav-90ffb886ce064ba838eebb25ec72a17e.sample"] - -[params] - -force/8_bit=false -force/mono=false -force/max_rate=false -force/max_rate_hz=44100 -edit/trim=false -edit/normalize=false -edit/loop_mode=1 -edit/loop_begin=0 -edit/loop_end=1044956 -compress/mode=0 diff --git a/audio/sfx/fishing/bobber.wav b/audio/sfx/fishing/bobber.wav deleted file mode 100644 index 8c9d916..0000000 Binary files a/audio/sfx/fishing/bobber.wav and /dev/null differ diff --git a/audio/sfx/fishing/bobber.wav.import b/audio/sfx/fishing/bobber.wav.import deleted file mode 100644 index d5fc82d..0000000 --- a/audio/sfx/fishing/bobber.wav.import +++ /dev/null @@ -1,24 +0,0 @@ -[remap] - -importer="wav" -type="AudioStreamWAV" -uid="uid://sxydt4wnmrj3" -path="res://.godot/imported/bobber.wav-b435bb251a112445f1ddebcacc74804a.sample" - -[deps] - -source_file="res://audio/sfx/fishing/bobber.wav" -dest_files=["res://.godot/imported/bobber.wav-b435bb251a112445f1ddebcacc74804a.sample"] - -[params] - -force/8_bit=false -force/mono=false -force/max_rate=false -force/max_rate_hz=44100 -edit/trim=false -edit/normalize=false -edit/loop_mode=0 -edit/loop_begin=0 -edit/loop_end=-1 -compress/mode=2 diff --git a/audio/sfx/fishing/fighting.wav b/audio/sfx/fishing/fighting.wav deleted file mode 100644 index f647069..0000000 Binary files a/audio/sfx/fishing/fighting.wav and /dev/null differ diff --git a/audio/sfx/fishing/fighting.wav.import b/audio/sfx/fishing/fighting.wav.import deleted file mode 100644 index ec59561..0000000 --- a/audio/sfx/fishing/fighting.wav.import +++ /dev/null @@ -1,24 +0,0 @@ -[remap] - -importer="wav" -type="AudioStreamWAV" -uid="uid://df6yg85cldetw" -path="res://.godot/imported/fighting.wav-1427843e18acf5134cc66d4a813033b6.sample" - -[deps] - -source_file="res://audio/sfx/fishing/fighting.wav" -dest_files=["res://.godot/imported/fighting.wav-1427843e18acf5134cc66d4a813033b6.sample"] - -[params] - -force/8_bit=false -force/mono=false -force/max_rate=false -force/max_rate_hz=44100 -edit/trim=false -edit/normalize=false -edit/loop_mode=1 -edit/loop_begin=0 -edit/loop_end=124487 -compress/mode=0 diff --git a/audio/sfx/fishing/reeling.wav b/audio/sfx/fishing/reeling.wav deleted file mode 100644 index 6be5d03..0000000 Binary files a/audio/sfx/fishing/reeling.wav and /dev/null differ diff --git a/audio/sfx/fishing/reeling.wav.import b/audio/sfx/fishing/reeling.wav.import deleted file mode 100644 index e5e6749..0000000 --- a/audio/sfx/fishing/reeling.wav.import +++ /dev/null @@ -1,24 +0,0 @@ -[remap] - -importer="wav" -type="AudioStreamWAV" -uid="uid://v4yjxtslbrd7" -path="res://.godot/imported/reeling.wav-97a9415ae2d9e7ca4c976bb15b10e6fd.sample" - -[deps] - -source_file="res://audio/sfx/fishing/reeling.wav" -dest_files=["res://.godot/imported/reeling.wav-97a9415ae2d9e7ca4c976bb15b10e6fd.sample"] - -[params] - -force/8_bit=false -force/mono=false -force/max_rate=false -force/max_rate_hz=44100 -edit/trim=false -edit/normalize=false -edit/loop_mode=1 -edit/loop_begin=0 -edit/loop_end=114628 -compress/mode=0 diff --git a/default_bus_layout.tres b/default_bus_layout.tres index 665b0e9..ca38684 100644 --- a/default_bus_layout.tres +++ b/default_bus_layout.tres @@ -13,9 +13,3 @@ bus/1/mute = false bus/1/bypass_fx = false bus/1/volume_db = 0.0 bus/1/send = &"Master" -bus/2/name = &"SFX" -bus/2/solo = false -bus/2/mute = false -bus/2/bypass_fx = false -bus/2/volume_db = 0.0 -bus/2/send = &"Master" diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index 373c800..0000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,72 +0,0 @@ -# Architecture - -## Composition - -`main/main.tscn` is the application composition root. It owns long-lived -services, the active world, player container, save/settings managers, and the -pixelated UI viewport. Services are scene-owned rather than global autoloads, -which makes their dependencies visible in the main scene and allows focused -tests to instantiate the same composition. - -The main script coordinates title, session, world, and UI lifecycle. Domain -logic remains in typed resources and services rather than being stored solely -in controls. - -## Domain boundaries - -- `fish/` defines species, availability, catches, pools, quality, and selection. -- `fishing/` owns cast/chase state and resolves authoritative fishing surfaces. -- `inventory/`, `items/`, `economy/`, `progression/`, and `jobs/` own persistent - player-facing game state. -- `world/` owns authored map composition and presentation. Water type is a - shared typed definition used by water bodies, fish habitat, fishing - validation, Logbook classification, and saltwater shoreline presentation. -- `ui/` observes and invokes domain services. It does not define stable item or - fish identity. - -Resource files (`.tres`) are authored data. Stable IDs, not display names or -node names, connect persistent and networked state to that data. - -## Networking - -`NetworkSession` owns ENet session lifecycle and peer registration. Dedicated -network services validate and replicate bounded domains such as fishing, -sales, shops, item use, profiles, jobs, mail, chat, drawings, time, and weather. - -The host is authoritative. Clients submit requests or evidence; the host -derives trusted context from registered peers, authoritative regions, and -server-owned state before mutating inventory, wallet, progression, or shared -world state. See [`decisions/0001-host-authority.md`](decisions/0001-host-authority.md). - -Protocol compatibility is defined in `network/network_protocol.gd`. A visible -release version is not a reason to change the protocol number. - -## Persistence - -`PlayerDataRoot` selects and validates a portable data root. Stores receive -paths from that owner rather than inventing unrelated locations. Progression is -written by `PlayerSaveManager`; device settings and social/identity stores have -separate formats and lifecycles. - -Save migrations are sequential and explicit. Existing catches and ownership -are keyed by stable IDs so authored metadata can evolve without rewriting -historical records. Current source constants—not documentation—are -authoritative for format versions. - -## Presentation - -Gameplay is rendered in 3D with the GL Compatibility renderer. The main UI is -presented through a uniformly scaled SubViewport. Shared UI components and -palette resources prevent page-specific geometry and style drift. - -World presentation systems (time/weather visuals, procedural sky and water, -shoreline ribbons, player blob shadows) do not own gameplay collision or -network authority. Generated shoreline meshes are deterministic presentation -resources baked from explicitly configured static terrain. - -## Validation - -Tests are executable Godot `SceneTree` scripts. Some are pure content/domain -checks, some instantiate the main scene, and multiplayer checks run paired host -and client processes on loopback. The repository runner provides isolation and -consistent entry points; see [`TESTING.md`](TESTING.md). diff --git a/docs/ASSET-PROVENANCE.md b/docs/ASSET-PROVENANCE.md deleted file mode 100644 index 9c3bc76..0000000 --- a/docs/ASSET-PROVENANCE.md +++ /dev/null @@ -1,109 +0,0 @@ -# Asset provenance - -This document records where runtime assets came from and what must be verified -before redistribution. A Git commit proves when bytes entered this repository; -it does not by itself prove authorship or licensing. - -## Intake policy - -For every new external or supplied asset, record: - -- creator or supplying party; -- original source location or delivery channel; -- source filename and repository destination; -- source and destination SHA-256 when copied without modification; -- license or explicit permission; -- any permitted transformations; -- the importing commit or release. - -Runtime resources must use `res://` paths. Workstation Sync folders are intake -locations only and must never appear in scenes or resources. - -## Current inventory - -| Asset family | Repository location | Recorded provenance | -| --- | --- | --- | -| Fish art and portraits | `fish/species/`, `art/exported/fish/` | 2D artwork by contributor Rheannon Eisworth. | -| Item icons | `items/icons/` | 2D artwork by contributor Rheannon Eisworth. | -| Inventory notepad | `art/ui/ui_notepad.png` | 2D artwork by contributor Rheannon Eisworth; integrated without a runtime external path. | -| Environment textures | `art/exported/environment/textures/` | 2D artwork by contributor Rheannon Eisworth. | -| UI patterns | `art/patterns/` | 2D artwork by contributor Rheannon Eisworth. | -| Character and world models | `art/exported/` | Original 3D models by the project owner. Any embedded 2D artwork is by Rheannon Eisworth. | -| Tuffy font | `ui/fonts/Tuffy_Bold.otf` | Public-domain dedication in `ui/fonts/Tuffy-LICENSE.txt`. | -| Seattle Avenue font | `ui/fonts/seattle_avenue.otf` | License and attribution not present; resolve before public distribution. | -| Title music | `audio/music/title/as_in_four_wolves.ogg` | Original music composed and owned by the project owner. | -| Fishing fight loop | `audio/sfx/fishing/fighting.wav` | Edited from “Spinning reel.wav” by Freesound user tosha73, sound 509902, CC0. | -| Manual-reeling loop | `audio/sfx/fishing/reeling.wav` | Edited from the same CC0 “Spinning reel.wav” source. | -| Saltwater wave ambience | `audio/ambience/waves.wav` | “Gentle Ocean Waves Loop” by Freesound user kkenny101, sound 852826, CC0. | -| Bobber water impact | `audio/sfx/fishing/bobber.wav` | “Quick Water Droplet” by Freesound user qubodup, sound 792931, CC0. | - -### Fishing fight loop source record - -- Source page: https://freesound.org/s/509902/ -- Creator: tosha73 -- Source title: `Spinning reel.wav` -- License: Creative Commons Zero (CC0) -- Downloaded source filename: `509902__tosha73__spinning-reel.wav` -- Downloaded source SHA-256: - `9741afdb1ec9c73f5e039f0e5ac174998cb0a1f737b626531e63919d4d232fad` -- Audacity working project: `fighting.aup3` -- Audacity project SHA-256: - `9928f077ecf48d01416f8d05700707e1b07d0f731846db80e27116f5b82dbbf5` -- Runtime edit source/destination SHA-256: - `b6f3f2f94bfaf9254ac04dd96b1fd28c15e1011a1db44bb3e70eeaa95de3c212` -- Runtime format: 48 kHz, 16-bit, stereo PCM WAV; 2.593479 seconds; - configured as a forward loop by the fishing presentation. -- Manual-reeling Audacity project: `reeling.aup3` -- Manual-reeling Audacity project SHA-256: - `20ad52f6bdd16ae6561f06f8355fe309e95023e815053fd5dfbd5a5ce3c1f9f9` -- Manual-reeling runtime source/destination SHA-256: - `e403d5b7c8af1da4b28599cc0f51de3eda70d9e9296db27852fe7dc95617a29d` -- Manual-reeling runtime format: 48 kHz, 16-bit, stereo PCM WAV; - 2.388083 seconds; configured as a forward loop. -- The downloaded source and Audacity projects remain in the project owner's - source-work archive; only the finished runtime edits ship in the game. - -### Saltwater wave ambience source record - -- Source page: https://freesound.org/s/852826/ -- Creator: kkenny101 -- Source title: `Gentle Ocean Waves Loop` -- License: Creative Commons Zero (CC0) -- Downloaded source filename: - `852826__kkenny101__gentle-ocean-waves-loop.wav` -- Downloaded source and runtime source/destination SHA-256: - `f93e9890583f072ac52cf197b8b5942397d3d5e889fbdb9112a0776142f50229` -- Runtime format: 48 kHz, 24-bit, mono PCM WAV; 21.769917 seconds; - configured as a forward loop. -- The downloaded source remains in the project owner's source-work archive; - only the finished runtime loop ships in the game. - -### Bobber water-impact source record - -- Source page: https://freesound.org/s/792931/ -- Creator: qubodup -- Source title: `Quick Water Droplet` -- License: Creative Commons Zero (CC0) -- Downloaded source filename: `792931__qubodup__quick-water-droplet.wav` -- Downloaded source and runtime source/destination SHA-256: - `aef0d16384efed4a7b071c4d80c21597617f882f4e0c1d5295ac194d315eafb7` -- Runtime format: 48 kHz, 16-bit, mono PCM WAV; 0.197146 seconds; one-shot. -- The downloaded source remains in the project owner's source-work archive; - only the finished runtime sound ships in the game. - -## Generated resources - -Godot `.import` sidecars and deterministic shoreline `.tres` meshes are derived -repository resources, not original artwork. `.godot/imported/`, editor caches, -captures, exports, and temporary test data are not tracked. - -## Release gate - -Before a public binary or source release: - -1. Resolve the Seattle Avenue font license and attribution gap above. -2. Record the public owner/studio credit and the contributor's redistribution - permission in the chosen project license or release records. -3. Confirm the project-wide source/content license selected by the owner. -4. Search exported resources for external filesystem paths. -5. Preserve required third-party notices with the package. diff --git a/docs/BALANCE.md b/docs/BALANCE.md deleted file mode 100644 index 948b882..0000000 --- a/docs/BALANCE.md +++ /dev/null @@ -1,41 +0,0 @@ -# Balance and content notes - -Balance is authored data and should change deliberately. This document records -the policy; exact current values remain authoritative in `.tres` resources and -typed scripts. - -## Fish - -- Stable fish IDs and catalog numbers must not be changed for display cleanup. -- Species availability may constrain water type, time, weather, bait, and other - authored context. -- Location pools control selection weight; the global catalog remains - comprehensive. -- Freshwater/saltwater habitat is validated by the host in addition to pool - membership. -- Value, rarity, quality, and weight ranges should be reviewed together because - they affect economy and catch difficulty. - -## Economy and progression - -- Sales and purchases are host-authoritative and must mutate inventory and - wallet exactly once. -- Reserved assets are rejected atomically; mixed valid/reserved batches must - not partially succeed. -- Item effects, shop prices, cooler capacity, fishing upgrades, jobs, and - experience are separate balance axes. Avoid changing several in an unrelated - presentation pass. - -## Recording a balance change - -Include in the change description: - -1. affected stable IDs and resource paths; -2. old and new values; -3. intended player-facing outcome; -4. interactions with quality, availability, and economy; -5. deterministic validation performed; -6. whether existing saves remain semantically valid. - -Do not bump the save schema or network protocol simply because an authored -number changed. Bump a format only when its serialized contract changes. diff --git a/docs/TESTING.md b/docs/TESTING.md deleted file mode 100644 index e70455b..0000000 --- a/docs/TESTING.md +++ /dev/null @@ -1,63 +0,0 @@ -# Testing - -NETfishing validations are Godot `SceneTree` scripts. They use assertions and -exit nonzero on failure. Run them with isolated user data so development checks -cannot touch real saves, identity, trust, relationships, or settings. - -## Consolidated runner - -```sh -scripts/run_validations.sh quick -scripts/run_validations.sh full -scripts/run_validations.sh host -scripts/run_validations.sh network -scripts/run_validations.sh all -scripts/run_validations.sh --list -``` - -- `quick` runs deterministic content and domain validations. -- `full` adds socket-free scene/runtime checks suitable for headless execution. -- `host` runs single-process authoritative-host checks that bind a local UDP - port. -- `network` runs the loopback host/client validations in pairs. -- `all` runs `full`, `host`, and then `network`. - -Set `GODOT_BIN` to select another executable. Set `TEST_TIMEOUT_SECONDS` to -change the per-process timeout. The runner creates one temporary XDG root per -process and removes it on exit. - -## One focused test - -```sh -test_root="$(mktemp -d)" -XDG_DATA_HOME="$test_root/data" \ -XDG_CONFIG_HOME="$test_root/config" \ -godot --headless --path . --script tests/fish_catalog_content_validation.gd -rm -rf -- "$test_root" -``` - -Do not set `NETFISHING_DATA_DIR` to an arbitrary empty folder: that variable is -an explicit portable-data override and must point at a valid NETfishing data -root. Isolating XDG paths is sufficient for the validation scripts. - -## Graphical checks - -Headless tests cannot prove visual alignment, actual mouse routing, shader -appearance, controller feel, or window-resize behavior. Presentation changes -need a real graphical startup with isolated XDG roots and inspection at the -canonical 1280×720 layout plus relevant low/high and ultrawide resolutions. - -## Network checks - -Host and paired tests bind loopback UDP ports defined in their scripts. Ensure -no old Godot validation process is holding those ports and that the execution -environment permits local sockets. The runner starts paired hosts before their -clients and requires both processes to exit successfully. Network tests do not -contact external servers. - -## Release checks - -A release audit additionally includes clean Git/tag verification, editor import, -export-template checks, platform exports, executable smoke tests, archive -inspection, and SHA-256 verification. Those checks are intentionally not hidden -inside the development runner. diff --git a/docs/decisions/0001-host-authority.md b/docs/decisions/0001-host-authority.md deleted file mode 100644 index f134d93..0000000 --- a/docs/decisions/0001-host-authority.md +++ /dev/null @@ -1,27 +0,0 @@ -# ADR 0001: Host-authoritative shared state - -Status: accepted - -## Context - -NETfishing supports private hosts, open hosts, and joined clients. Catches, -currency, owned items, jobs, mail, drawings, profiles, and moderation affect -state that cannot safely trust a client's local presentation. - -## Decision - -The host validates requests against registered peers and host-owned context, -then performs the authoritative mutation. Clients receive results and replicated -presentation state. Client evidence is bounded and reconstructed where -possible; it is not treated as authority. - -Private single-player uses the same host path. Presentation-only state does not -add RPCs or persistence. - -## Consequences - -- Shared behavior is consistent across private, open-host, and joined-client - modes. -- Tests must cover local-host and paired host/client paths. -- Stable protocol payloads and rejection cleanup require explicit handling. -- UI activation cannot be used as proof that a server-side mutation succeeded. diff --git a/docs/decisions/0002-authored-data-and-stable-ids.md b/docs/decisions/0002-authored-data-and-stable-ids.md deleted file mode 100644 index 23163cb..0000000 --- a/docs/decisions/0002-authored-data-and-stable-ids.md +++ /dev/null @@ -1,27 +0,0 @@ -# ADR 0002: Authored resources and stable identifiers - -Status: accepted - -## Context - -Fish, items, pools, availability, shop stock, and other game content evolve -independently from saved catches and network messages. Display labels and scene -node names are expected to change during development. - -## Decision - -Repository-owned resources are the authoritative authored data. Persistent and -networked records refer to stable IDs. Display names, filenames, node names, -coordinates, and pool names are not compatibility identifiers. - -Cross-domain concepts such as water type use one typed definition rather than -duplicated strings. Comprehensive catalogs remain separate from location- -specific selection pools. - -## Consequences - -- Renaming visible UI does not require save migration. -- Removing or changing a stable ID requires an explicit compatibility plan. -- Content validation checks uniqueness, catalog completeness, pool membership, - and typed habitat compatibility. -- New authored assets need provenance records as well as resource references. diff --git a/fish/pools/fish_catalog.tres b/fish/pools/fish_catalog.tres index d646449..66a1c34 100644 --- a/fish/pools/fish_catalog.tres +++ b/fish/pools/fish_catalog.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" load_steps=21 format=3] +[gd_resource type="Resource" load_steps=10 format=3] [ext_resource type="Script" path="res://fish/fish_pool.gd" id="1_pool"] [ext_resource type="Resource" path="res://fish/species/bluegill/bluegill.tres" id="2_bluegill"] @@ -9,18 +9,7 @@ [ext_resource type="Resource" path="res://fish/species/catfish_channel/catfish_channel.tres" id="7_catfish_channel"] [ext_resource type="Resource" path="res://fish/species/catfish_flathead/catfish_flathead.tres" id="8_catfish_flathead"] [ext_resource type="Resource" path="res://fish/species/catfish_white/catfish_white.tres" id="9_catfish_white"] -[ext_resource type="Resource" path="res://fish/species/tuna_albacore/tuna_albacore.tres" id="10_tuna_albacore"] -[ext_resource type="Resource" path="res://fish/species/tuna_bigeye/tuna_bigeye.tres" id="11_tuna_bigeye"] -[ext_resource type="Resource" path="res://fish/species/tuna_bluefin/tuna_bluefin.tres" id="12_tuna_bluefin"] -[ext_resource type="Resource" path="res://fish/species/tuna_skipjack/tuna_skipjack.tres" id="13_tuna_skipjack"] -[ext_resource type="Resource" path="res://fish/species/tuna_yellowfin/tuna_yellowfin.tres" id="14_tuna_yellowfin"] -[ext_resource type="Resource" path="res://fish/species/goby_round/goby_round.tres" id="15_goby_round"] -[ext_resource type="Resource" path="res://fish/species/salmon_atlantic/salmon_atlantic.tres" id="16_salmon_atlantic"] -[ext_resource type="Resource" path="res://fish/species/salmon_chum/salmon_chum.tres" id="17_salmon_chum"] -[ext_resource type="Resource" path="res://fish/species/salmon_coho/salmon_coho.tres" id="18_salmon_coho"] -[ext_resource type="Resource" path="res://fish/species/salmon_pink/salmon_pink.tres" id="19_salmon_pink"] -[ext_resource type="Resource" path="res://fish/species/salmon_sockeye/salmon_sockeye.tres" id="20_salmon_sockeye"] [resource] script = ExtResource("1_pool") -candidates = [ExtResource("2_bluegill"), ExtResource("3_bass"), ExtResource("4_carp"), ExtResource("5_sunfish"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white"), ExtResource("10_tuna_albacore"), ExtResource("11_tuna_bigeye"), ExtResource("12_tuna_bluefin"), ExtResource("13_tuna_skipjack"), ExtResource("14_tuna_yellowfin"), ExtResource("15_goby_round"), ExtResource("16_salmon_atlantic"), ExtResource("17_salmon_chum"), ExtResource("18_salmon_coho"), ExtResource("19_salmon_pink"), ExtResource("20_salmon_sockeye")] +candidates = [ExtResource("2_bluegill"), ExtResource("3_bass"), ExtResource("4_carp"), ExtResource("5_sunfish"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white")] diff --git a/fish/pools/starter_ocean_pool.tres b/fish/pools/starter_ocean_pool.tres index 8772d68..a84106e 100644 --- a/fish/pools/starter_ocean_pool.tres +++ b/fish/pools/starter_ocean_pool.tres @@ -1,19 +1,9 @@ -[gd_resource type="Resource" load_steps=14 format=3] +[gd_resource type="Resource" load_steps=4 format=3] [ext_resource type="Script" path="res://fish/fish_pool.gd" id="1_pool"] [ext_resource type="Resource" path="res://fish/species/bass/bass.tres" id="2_bass"] [ext_resource type="Resource" path="res://fish/species/sunfish/sunfish.tres" id="3_sunfish"] -[ext_resource type="Resource" path="res://fish/species/tuna_albacore/tuna_albacore.tres" id="4_tuna_albacore"] -[ext_resource type="Resource" path="res://fish/species/tuna_bigeye/tuna_bigeye.tres" id="5_tuna_bigeye"] -[ext_resource type="Resource" path="res://fish/species/tuna_bluefin/tuna_bluefin.tres" id="6_tuna_bluefin"] -[ext_resource type="Resource" path="res://fish/species/tuna_skipjack/tuna_skipjack.tres" id="7_tuna_skipjack"] -[ext_resource type="Resource" path="res://fish/species/tuna_yellowfin/tuna_yellowfin.tres" id="8_tuna_yellowfin"] -[ext_resource type="Resource" path="res://fish/species/salmon_atlantic/salmon_atlantic.tres" id="9_salmon_atlantic"] -[ext_resource type="Resource" path="res://fish/species/salmon_chum/salmon_chum.tres" id="10_salmon_chum"] -[ext_resource type="Resource" path="res://fish/species/salmon_coho/salmon_coho.tres" id="11_salmon_coho"] -[ext_resource type="Resource" path="res://fish/species/salmon_pink/salmon_pink.tres" id="12_salmon_pink"] -[ext_resource type="Resource" path="res://fish/species/salmon_sockeye/salmon_sockeye.tres" id="13_salmon_sockeye"] [resource] script = ExtResource("1_pool") -candidates = [ExtResource("2_bass"), ExtResource("3_sunfish"), ExtResource("4_tuna_albacore"), ExtResource("5_tuna_bigeye"), ExtResource("6_tuna_bluefin"), ExtResource("7_tuna_skipjack"), ExtResource("8_tuna_yellowfin"), ExtResource("9_salmon_atlantic"), ExtResource("10_salmon_chum"), ExtResource("11_salmon_coho"), ExtResource("12_salmon_pink"), ExtResource("13_salmon_sockeye")] +candidates = [ExtResource("2_bass"), ExtResource("3_sunfish")] diff --git a/fish/pools/starter_pond_pool.tres b/fish/pools/starter_pond_pool.tres index 276aaa5..a594d72 100644 --- a/fish/pools/starter_pond_pool.tres +++ b/fish/pools/starter_pond_pool.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" load_steps=9 format=3] +[gd_resource type="Resource" load_steps=8 format=3] [ext_resource type="Script" path="res://fish/fish_pool.gd" id="1_pool"] [ext_resource type="Resource" path="res://fish/species/bluegill/bluegill.tres" id="2_bluegill"] @@ -7,8 +7,7 @@ [ext_resource type="Resource" path="res://fish/species/catfish_channel/catfish_channel.tres" id="7_catfish_channel"] [ext_resource type="Resource" path="res://fish/species/catfish_flathead/catfish_flathead.tres" id="8_catfish_flathead"] [ext_resource type="Resource" path="res://fish/species/catfish_white/catfish_white.tres" id="9_catfish_white"] -[ext_resource type="Resource" path="res://fish/species/goby_round/goby_round.tres" id="10_goby_round"] [resource] script = ExtResource("1_pool") -candidates = [ExtResource("2_bluegill"), ExtResource("4_carp"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white"), ExtResource("10_goby_round")] +candidates = [ExtResource("2_bluegill"), ExtResource("4_carp"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white")] diff --git a/fish/species/goby_round/fish_goby_round.png b/fish/species/goby_round/fish_goby_round.png deleted file mode 100644 index 89e3f78..0000000 Binary files a/fish/species/goby_round/fish_goby_round.png and /dev/null differ diff --git a/fish/species/goby_round/fish_goby_round.png.import b/fish/species/goby_round/fish_goby_round.png.import deleted file mode 100644 index 6fb96e8..0000000 --- a/fish/species/goby_round/fish_goby_round.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bdhywe0r1xcio" -path="res://.godot/imported/fish_goby_round.png-3c3fd3dd06c7b5dd4539ab186bf0d865.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/goby_round/fish_goby_round.png" -dest_files=["res://.godot/imported/fish_goby_round.png-3c3fd3dd06c7b5dd4539ab186bf0d865.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/goby_round/goby_round.tres b/fish/species/goby_round/goby_round.tres deleted file mode 100644 index 44aa8fa..0000000 --- a/fish/species/goby_round/goby_round.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/common_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/goby_round/fish_goby_round.png" id="4_texture"] - -[sub_resource type="Resource" id="RoundGobyAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"worm", &"minnow"]) -preferred_bait_weight_multiplier = 1.35 - -[resource] -script = ExtResource("1_fish_data") -id = &"goby_round" -display_name = "round goby" -allowed_water_types = 1 -rarity = 0 -base_catch_weight = 8.0 -catch_profile = ExtResource("2_profile") -availability = SubResource("RoundGobyAvailability") -weight_min_lb = 0.1 -weight_max_lb = 0.6 -display_scale_min = 0.55 -display_scale_max = 0.9 -display_scale_curve = 1.0 -sell_value_min = 2 -sell_value_max = 3 -sell_value_curve = 1.0 -display_texture = ExtResource("4_texture") diff --git a/fish/species/salmon_atlantic/fish_salmon_atlantic.png b/fish/species/salmon_atlantic/fish_salmon_atlantic.png deleted file mode 100644 index ea6164b..0000000 Binary files a/fish/species/salmon_atlantic/fish_salmon_atlantic.png and /dev/null differ diff --git a/fish/species/salmon_atlantic/fish_salmon_atlantic.png.import b/fish/species/salmon_atlantic/fish_salmon_atlantic.png.import deleted file mode 100644 index 36fb242..0000000 --- a/fish/species/salmon_atlantic/fish_salmon_atlantic.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ddbclfu5wtd5r" -path="res://.godot/imported/fish_salmon_atlantic.png-e11e70a37a78573bfb86a21b48ae319b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/salmon_atlantic/fish_salmon_atlantic.png" -dest_files=["res://.godot/imported/fish_salmon_atlantic.png-e11e70a37a78573bfb86a21b48ae319b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/salmon_atlantic/salmon_atlantic.tres b/fish/species/salmon_atlantic/salmon_atlantic.tres deleted file mode 100644 index 886b348..0000000 --- a/fish/species/salmon_atlantic/salmon_atlantic.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/salmon_atlantic/fish_salmon_atlantic.png" id="4_texture"] - -[sub_resource type="Resource" id="AtlanticSalmonAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"salmon_atlantic" -display_name = "atlantic salmon" -allowed_water_types = 2 -rarity = 3 -base_catch_weight = 0.65 -catch_profile = ExtResource("2_profile") -availability = SubResource("AtlanticSalmonAvailability") -weight_min_lb = 8.0 -weight_max_lb = 40.0 -display_scale_min = 1.05 -display_scale_max = 1.9 -display_scale_curve = 0.85 -sell_value_min = 20 -sell_value_max = 42 -sell_value_curve = 0.85 -display_texture = ExtResource("4_texture") diff --git a/fish/species/salmon_chum/fish_salmon_chum.png b/fish/species/salmon_chum/fish_salmon_chum.png deleted file mode 100644 index 920b39d..0000000 Binary files a/fish/species/salmon_chum/fish_salmon_chum.png and /dev/null differ diff --git a/fish/species/salmon_chum/fish_salmon_chum.png.import b/fish/species/salmon_chum/fish_salmon_chum.png.import deleted file mode 100644 index 587b83b..0000000 --- a/fish/species/salmon_chum/fish_salmon_chum.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqjkmd6l1a2i4" -path="res://.godot/imported/fish_salmon_chum.png-78c86aca1218255db2c488a5c22e4409.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/salmon_chum/fish_salmon_chum.png" -dest_files=["res://.godot/imported/fish_salmon_chum.png-78c86aca1218255db2c488a5c22e4409.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/salmon_chum/salmon_chum.tres b/fish/species/salmon_chum/salmon_chum.tres deleted file mode 100644 index 2ce0f20..0000000 --- a/fish/species/salmon_chum/salmon_chum.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/salmon_chum/fish_salmon_chum.png" id="4_texture"] - -[sub_resource type="Resource" id="ChumSalmonAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"salmon_chum" -display_name = "chum salmon" -allowed_water_types = 2 -rarity = 1 -base_catch_weight = 2.5 -catch_profile = ExtResource("2_profile") -availability = SubResource("ChumSalmonAvailability") -weight_min_lb = 6.0 -weight_max_lb = 25.0 -display_scale_min = 1.0 -display_scale_max = 1.75 -display_scale_curve = 0.9 -sell_value_min = 10 -sell_value_max = 22 -sell_value_curve = 0.9 -display_texture = ExtResource("4_texture") diff --git a/fish/species/salmon_coho/fish_salmon_coho.png b/fish/species/salmon_coho/fish_salmon_coho.png deleted file mode 100644 index 2caf696..0000000 Binary files a/fish/species/salmon_coho/fish_salmon_coho.png and /dev/null differ diff --git a/fish/species/salmon_coho/fish_salmon_coho.png.import b/fish/species/salmon_coho/fish_salmon_coho.png.import deleted file mode 100644 index 1cd3254..0000000 --- a/fish/species/salmon_coho/fish_salmon_coho.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c4c4e43lbr88c" -path="res://.godot/imported/fish_salmon_coho.png-fc57b7ff3c0ac63ccfec6db9cec1dedb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/salmon_coho/fish_salmon_coho.png" -dest_files=["res://.godot/imported/fish_salmon_coho.png-fc57b7ff3c0ac63ccfec6db9cec1dedb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/salmon_coho/salmon_coho.tres b/fish/species/salmon_coho/salmon_coho.tres deleted file mode 100644 index 66203de..0000000 --- a/fish/species/salmon_coho/salmon_coho.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/salmon_coho/fish_salmon_coho.png" id="4_texture"] - -[sub_resource type="Resource" id="CohoSalmonAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"salmon_coho" -display_name = "coho salmon" -allowed_water_types = 2 -rarity = 2 -base_catch_weight = 1.4 -catch_profile = ExtResource("2_profile") -availability = SubResource("CohoSalmonAvailability") -weight_min_lb = 5.0 -weight_max_lb = 30.0 -display_scale_min = 1.0 -display_scale_max = 1.8 -display_scale_curve = 0.88 -sell_value_min = 14 -sell_value_max = 28 -sell_value_curve = 0.88 -display_texture = ExtResource("4_texture") diff --git a/fish/species/salmon_pink/fish_salmon_pink.png b/fish/species/salmon_pink/fish_salmon_pink.png deleted file mode 100644 index 85b1d88..0000000 Binary files a/fish/species/salmon_pink/fish_salmon_pink.png and /dev/null differ diff --git a/fish/species/salmon_pink/fish_salmon_pink.png.import b/fish/species/salmon_pink/fish_salmon_pink.png.import deleted file mode 100644 index caf4c74..0000000 --- a/fish/species/salmon_pink/fish_salmon_pink.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bk27bsdrtlqap" -path="res://.godot/imported/fish_salmon_pink.png-0c9ca3bc540b868c12fe32b1cdc59249.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/salmon_pink/fish_salmon_pink.png" -dest_files=["res://.godot/imported/fish_salmon_pink.png-0c9ca3bc540b868c12fe32b1cdc59249.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/salmon_pink/salmon_pink.tres b/fish/species/salmon_pink/salmon_pink.tres deleted file mode 100644 index a6b74d5..0000000 --- a/fish/species/salmon_pink/salmon_pink.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/salmon_pink/fish_salmon_pink.png" id="4_texture"] - -[sub_resource type="Resource" id="PinkSalmonAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"salmon_pink" -display_name = "pink salmon" -allowed_water_types = 2 -rarity = 1 -base_catch_weight = 3.0 -catch_profile = ExtResource("2_profile") -availability = SubResource("PinkSalmonAvailability") -weight_min_lb = 3.0 -weight_max_lb = 12.0 -display_scale_min = 0.9 -display_scale_max = 1.55 -display_scale_curve = 0.92 -sell_value_min = 8 -sell_value_max = 15 -sell_value_curve = 0.92 -display_texture = ExtResource("4_texture") diff --git a/fish/species/salmon_sockeye/fish_salmon_sockeye.png b/fish/species/salmon_sockeye/fish_salmon_sockeye.png deleted file mode 100644 index bb98433..0000000 Binary files a/fish/species/salmon_sockeye/fish_salmon_sockeye.png and /dev/null differ diff --git a/fish/species/salmon_sockeye/fish_salmon_sockeye.png.import b/fish/species/salmon_sockeye/fish_salmon_sockeye.png.import deleted file mode 100644 index 71a8856..0000000 --- a/fish/species/salmon_sockeye/fish_salmon_sockeye.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmokm3sra4ai8" -path="res://.godot/imported/fish_salmon_sockeye.png-99d566111b5cad1e6ae4702b6f9128fd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/salmon_sockeye/fish_salmon_sockeye.png" -dest_files=["res://.godot/imported/fish_salmon_sockeye.png-99d566111b5cad1e6ae4702b6f9128fd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/salmon_sockeye/salmon_sockeye.tres b/fish/species/salmon_sockeye/salmon_sockeye.tres deleted file mode 100644 index 54e6bff..0000000 --- a/fish/species/salmon_sockeye/salmon_sockeye.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/salmon_sockeye/fish_salmon_sockeye.png" id="4_texture"] - -[sub_resource type="Resource" id="SockeyeSalmonAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"salmon_sockeye" -display_name = "sockeye salmon" -allowed_water_types = 2 -rarity = 2 -base_catch_weight = 1.6 -catch_profile = ExtResource("2_profile") -availability = SubResource("SockeyeSalmonAvailability") -weight_min_lb = 4.0 -weight_max_lb = 15.0 -display_scale_min = 0.95 -display_scale_max = 1.6 -display_scale_curve = 0.9 -sell_value_min = 12 -sell_value_max = 24 -sell_value_curve = 0.9 -display_texture = ExtResource("4_texture") diff --git a/fish/species/tuna_albacore/fish_tuna_albacore.png b/fish/species/tuna_albacore/fish_tuna_albacore.png deleted file mode 100644 index 3769c08..0000000 Binary files a/fish/species/tuna_albacore/fish_tuna_albacore.png and /dev/null differ diff --git a/fish/species/tuna_albacore/fish_tuna_albacore.png.import b/fish/species/tuna_albacore/fish_tuna_albacore.png.import deleted file mode 100644 index f2e6b6f..0000000 --- a/fish/species/tuna_albacore/fish_tuna_albacore.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bxebn81i552fg" -path="res://.godot/imported/fish_tuna_albacore.png-aaac5d00c8a250b19db99d7069f549e1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/tuna_albacore/fish_tuna_albacore.png" -dest_files=["res://.godot/imported/fish_tuna_albacore.png-aaac5d00c8a250b19db99d7069f549e1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/tuna_albacore/tuna_albacore.tres b/fish/species/tuna_albacore/tuna_albacore.tres deleted file mode 100644 index f98cd96..0000000 --- a/fish/species/tuna_albacore/tuna_albacore.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/tuna_albacore/fish_tuna_albacore.png" id="4_texture"] - -[sub_resource type="Resource" id="AlbacoreAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"tuna_albacore" -display_name = "albacore tuna" -allowed_water_types = 2 -rarity = 2 -base_catch_weight = 1.5 -catch_profile = ExtResource("2_profile") -availability = SubResource("AlbacoreAvailability") -weight_min_lb = 10.0 -weight_max_lb = 45.0 -display_scale_min = 1.1 -display_scale_max = 1.9 -display_scale_curve = 0.85 -sell_value_min = 12 -sell_value_max = 24 -sell_value_curve = 0.85 -display_texture = ExtResource("4_texture") diff --git a/fish/species/tuna_bigeye/fish_tuna_bigeye.png b/fish/species/tuna_bigeye/fish_tuna_bigeye.png deleted file mode 100644 index b4a36c3..0000000 Binary files a/fish/species/tuna_bigeye/fish_tuna_bigeye.png and /dev/null differ diff --git a/fish/species/tuna_bigeye/fish_tuna_bigeye.png.import b/fish/species/tuna_bigeye/fish_tuna_bigeye.png.import deleted file mode 100644 index 3539d10..0000000 --- a/fish/species/tuna_bigeye/fish_tuna_bigeye.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bypnhqmkhnm2c" -path="res://.godot/imported/fish_tuna_bigeye.png-1c20be325f0bac055325a6fa0ad17dd1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/tuna_bigeye/fish_tuna_bigeye.png" -dest_files=["res://.godot/imported/fish_tuna_bigeye.png-1c20be325f0bac055325a6fa0ad17dd1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/tuna_bigeye/tuna_bigeye.tres b/fish/species/tuna_bigeye/tuna_bigeye.tres deleted file mode 100644 index 618c7d3..0000000 --- a/fish/species/tuna_bigeye/tuna_bigeye.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/tuna_bigeye/fish_tuna_bigeye.png" id="4_texture"] - -[sub_resource type="Resource" id="BigeyeAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"tuna_bigeye" -display_name = "bigeye tuna" -allowed_water_types = 2 -rarity = 3 -base_catch_weight = 0.55 -catch_profile = ExtResource("2_profile") -availability = SubResource("BigeyeAvailability") -weight_min_lb = 20.0 -weight_max_lb = 120.0 -display_scale_min = 1.2 -display_scale_max = 2.2 -display_scale_curve = 0.8 -sell_value_min = 22 -sell_value_max = 48 -sell_value_curve = 0.8 -display_texture = ExtResource("4_texture") diff --git a/fish/species/tuna_bluefin/fish_tuna_bluefin.png b/fish/species/tuna_bluefin/fish_tuna_bluefin.png deleted file mode 100644 index a2b3cad..0000000 Binary files a/fish/species/tuna_bluefin/fish_tuna_bluefin.png and /dev/null differ diff --git a/fish/species/tuna_bluefin/fish_tuna_bluefin.png.import b/fish/species/tuna_bluefin/fish_tuna_bluefin.png.import deleted file mode 100644 index 674a0b7..0000000 --- a/fish/species/tuna_bluefin/fish_tuna_bluefin.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dg7nafydp4flx" -path="res://.godot/imported/fish_tuna_bluefin.png-04ec876b3a78ea716b7a0673e8497fab.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/tuna_bluefin/fish_tuna_bluefin.png" -dest_files=["res://.godot/imported/fish_tuna_bluefin.png-04ec876b3a78ea716b7a0673e8497fab.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/tuna_bluefin/tuna_bluefin.tres b/fish/species/tuna_bluefin/tuna_bluefin.tres deleted file mode 100644 index 50591c3..0000000 --- a/fish/species/tuna_bluefin/tuna_bluefin.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/tuna_bluefin/fish_tuna_bluefin.png" id="4_texture"] - -[sub_resource type="Resource" id="BluefinAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"tuna_bluefin" -display_name = "bluefin tuna" -allowed_water_types = 2 -rarity = 4 -base_catch_weight = 0.18 -catch_profile = ExtResource("2_profile") -availability = SubResource("BluefinAvailability") -weight_min_lb = 30.0 -weight_max_lb = 250.0 -display_scale_min = 1.3 -display_scale_max = 2.5 -display_scale_curve = 0.78 -sell_value_min = 35 -sell_value_max = 90 -sell_value_curve = 0.78 -display_texture = ExtResource("4_texture") diff --git a/fish/species/tuna_skipjack/fish_tuna_skipjack.png b/fish/species/tuna_skipjack/fish_tuna_skipjack.png deleted file mode 100644 index 5a7f74d..0000000 Binary files a/fish/species/tuna_skipjack/fish_tuna_skipjack.png and /dev/null differ diff --git a/fish/species/tuna_skipjack/fish_tuna_skipjack.png.import b/fish/species/tuna_skipjack/fish_tuna_skipjack.png.import deleted file mode 100644 index 786e985..0000000 --- a/fish/species/tuna_skipjack/fish_tuna_skipjack.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vvtr81d2aojs" -path="res://.godot/imported/fish_tuna_skipjack.png-98d7d6a76fc86bd76f861358be0635c7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/tuna_skipjack/fish_tuna_skipjack.png" -dest_files=["res://.godot/imported/fish_tuna_skipjack.png-98d7d6a76fc86bd76f861358be0635c7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/tuna_skipjack/tuna_skipjack.tres b/fish/species/tuna_skipjack/tuna_skipjack.tres deleted file mode 100644 index c1174e6..0000000 --- a/fish/species/tuna_skipjack/tuna_skipjack.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/tuna_skipjack/fish_tuna_skipjack.png" id="4_texture"] - -[sub_resource type="Resource" id="SkipjackAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"tuna_skipjack" -display_name = "skipjack tuna" -allowed_water_types = 2 -rarity = 1 -base_catch_weight = 3.0 -catch_profile = ExtResource("2_profile") -availability = SubResource("SkipjackAvailability") -weight_min_lb = 5.0 -weight_max_lb = 25.0 -display_scale_min = 1.0 -display_scale_max = 1.7 -display_scale_curve = 0.9 -sell_value_min = 8 -sell_value_max = 16 -sell_value_curve = 0.9 -display_texture = ExtResource("4_texture") diff --git a/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png b/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png deleted file mode 100644 index a1afc81..0000000 Binary files a/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png and /dev/null differ diff --git a/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png.import b/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png.import deleted file mode 100644 index a8918aa..0000000 --- a/fish/species/tuna_yellowfin/fish_tuna_yellowfin.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bwpdgagaysdsf" -path="res://.godot/imported/fish_tuna_yellowfin.png-14cd53683bfec6af599f1e1dc5728b99.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://fish/species/tuna_yellowfin/fish_tuna_yellowfin.png" -dest_files=["res://.godot/imported/fish_tuna_yellowfin.png-14cd53683bfec6af599f1e1dc5728b99.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/fish/species/tuna_yellowfin/tuna_yellowfin.tres b/fish/species/tuna_yellowfin/tuna_yellowfin.tres deleted file mode 100644 index 6fff5df..0000000 --- a/fish/species/tuna_yellowfin/tuna_yellowfin.tres +++ /dev/null @@ -1,30 +0,0 @@ -[gd_resource type="Resource" script_class="FishData" load_steps=5 format=3] - -[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] -[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] -[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] -[ext_resource type="Texture2D" path="res://fish/species/tuna_yellowfin/fish_tuna_yellowfin.png" id="4_texture"] - -[sub_resource type="Resource" id="YellowfinAvailability"] -script = ExtResource("3_availability_script") -preferred_bait_tags = Array[StringName]([&"minnow"]) -preferred_bait_weight_multiplier = 1.4 - -[resource] -script = ExtResource("1_fish_data") -id = &"tuna_yellowfin" -display_name = "yellowfin tuna" -allowed_water_types = 2 -rarity = 2 -base_catch_weight = 1.0 -catch_profile = ExtResource("2_profile") -availability = SubResource("YellowfinAvailability") -weight_min_lb = 15.0 -weight_max_lb = 80.0 -display_scale_min = 1.15 -display_scale_max = 2.1 -display_scale_curve = 0.82 -sell_value_min = 16 -sell_value_max = 36 -sell_value_curve = 0.82 -display_texture = ExtResource("4_texture") diff --git a/fishing/fishing_spot.gd b/fishing/fishing_spot.gd index 284b6de..a12427b 100644 --- a/fishing/fishing_spot.gd +++ b/fishing/fishing_spot.gd @@ -122,9 +122,6 @@ const NETWORK_INPUT_RESEND_INTERVAL_SECONDS: float = 0.1 @onready var _catch_controller: CatchControllerType = %CatchController @onready var _presentation: FishingPresentationType = %FishingPresentation -@onready var _bobber_audio: AudioStreamPlayer = %BobberAudio -@onready var _fight_audio: AudioStreamPlayer = %FightAudio -@onready var _reeling_audio: AudioStreamPlayer = %ReelingAudio var state: FishingState = FishingState.READY var _external_input_blocked: bool = false @@ -180,12 +177,6 @@ var _pending_cleanup_message: String = "" func _ready() -> void: _bite_rng.randomize() _configure_surface_resolver() - var fight_stream := _fight_audio.stream as AudioStreamWAV - if fight_stream != null: - _configure_audio_loop(fight_stream) - var reeling_stream := _reeling_audio.stream as AudioStreamWAV - if reeling_stream != null: - _configure_audio_loop(reeling_stream) _catch_controller.encounter_updated.connect(_on_catch_encounter_updated) _catch_controller.caught.connect(_on_catch_completed) _catch_controller.escaped.connect(_on_catch_escaped) @@ -232,15 +223,6 @@ func setup( _network_fishing = network_fishing _world_time = world_time _world_weather = world_weather - if ( - _network_session != null - and not _network_session.state_changed.is_connected( - _on_network_session_state_changed - ) - ): - _network_session.state_changed.connect( - _on_network_session_state_changed - ) if _network_fishing != null: _network_fishing.local_cast_accepted.connect( _on_network_cast_accepted @@ -366,7 +348,6 @@ func set_local_menu_input_suppressed( _local_menu_input_owners.erase(owner) if suppressed and state == FishingState.WAITING_FOR_BITE: _withdrawal_input_held = false - _stop_reeling_audio() _presentation.set_line_mode( FishingPresentationType.LineMode.SLACK ) @@ -376,7 +357,6 @@ func set_gameplay_input_enabled(enabled: bool) -> void: _gameplay_input_enabled = enabled if not enabled: _local_menu_input_owners.clear() - _stop_reeling_audio() func configure_accessibility_auto_click( @@ -420,8 +400,6 @@ func _secure_showcase_catch_for_recovery() -> void: func _exit_tree() -> void: - _stop_fight_audio() - _stop_reeling_audio() _showcase_restore_generation += 1 if ( state == FishingState.SHOWING_CATCH @@ -553,7 +531,6 @@ func _unhandled_input(event: InputEvent) -> void: return FishingState.WAITING_FOR_BITE: _withdrawal_input_held = true - _start_reeling_audio() if _network_fishing != null: _network_primary_input_held = true _network_input_resend_elapsed = 0.0 @@ -569,7 +546,6 @@ func _unhandled_input(event: InputEvent) -> void: get_viewport().set_input_as_handled() elif state == FishingState.WAITING_FOR_BITE: _withdrawal_input_held = false - _stop_reeling_audio() if _network_fishing != null: _network_primary_input_held = false _network_input_resend_elapsed = 0.0 @@ -755,7 +731,6 @@ func _on_cast_completed() -> void: if not _is_cast_target_valid(_cast_target): _cleanup_attempt("", &"invalid") return - _play_bobber_audio() if _network_fishing != null: _network_fishing.request_local_cast( _cast_origin_position, @@ -841,7 +816,6 @@ func _update_waiting_for_bite(delta: float) -> void: and not Input.is_action_pressed("fish_primary") ): _withdrawal_input_held = false - _stop_reeling_audio() _presentation.set_line_mode(FishingPresentationType.LineMode.SLACK) if not _withdrawal_input_held: @@ -934,7 +908,6 @@ func _activate_bite() -> void: if state != FishingState.WAITING_FOR_BITE: return - _stop_reeling_audio() if ( _active_player == null or _selected_fish == null @@ -950,7 +923,6 @@ func _activate_bite() -> void: if _pending_catch == null or not _pending_catch.is_valid(): _cancel_attempt() return - _start_fight_audio() bite_activated.emit() status_changed.emit("fish on!") _presentation.set_line_mode(FishingPresentationType.LineMode.TAUT) @@ -1029,7 +1001,6 @@ func _on_catch_completed() -> void: if _pending_catch == null or not _pending_catch.is_valid(): _cancel_attempt() return - _stop_fight_audio() state = FishingState.SHOWING_CATCH _showcase_ready = false _showcase_outcome_completed = false @@ -1043,7 +1014,6 @@ func _on_catch_escaped() -> void: if state != FishingState.FIGHTING: return - _stop_fight_audio() var fish_name: String = "the fish" if _selected_fish != null and not _selected_fish.display_name.is_empty(): fish_name = "the %s" % _selected_fish.display_name @@ -1150,8 +1120,6 @@ func _cleanup_attempt( cooldown_message: String = "", visual_outcome: StringName = &"", ) -> void: - _stop_fight_audio() - _stop_reeling_audio() if not visual_outcome.is_empty(): if state == FishingState.RETURNING: return @@ -1454,14 +1422,12 @@ func _on_network_cast_rejected(message: String) -> void: func _on_network_bite_started(_attempt_id: String) -> void: if state != FishingState.WAITING_FOR_BITE: return - _stop_reeling_audio() state = FishingState.FIGHTING _withdrawal_input_held = false _network_primary_input_held = Input.is_action_pressed("fish_primary") _network_input_resend_elapsed = 0.0 _network_auto_click_accumulator = 0.0 _network_active_barrier_index = -1 - _start_fight_audio() bite_activated.emit() status_changed.emit("fish on!") _presentation.set_line_mode(FishingPresentationType.LineMode.TAUT) @@ -1544,7 +1510,6 @@ func _update_network_auto_click(delta: float) -> void: func _on_network_catch_received(fish_catch: FishCatchType) -> void: if state != FishingState.FIGHTING or fish_catch == null: return - _stop_fight_audio() _pending_catch = fish_catch state = FishingState.SHOWING_CATCH _showcase_ready = false @@ -1576,57 +1541,6 @@ func _on_network_attempt_ended( _cleanup_attempt(message, visual_outcome) -func _on_network_session_state_changed(state_value: NetworkSession.State) -> void: - if state_value in [ - NetworkSession.State.INACTIVE, - NetworkSession.State.DISCONNECTING, - NetworkSession.State.CONNECTION_FAILED, - NetworkSession.State.SERVER_LOST, - ]: - _stop_fight_audio() - _stop_reeling_audio() - - -func _start_fight_audio() -> void: - if _fight_audio == null or _fight_audio.stream == null: - return - if not _fight_audio.playing: - _fight_audio.play() - - -func _play_bobber_audio() -> void: - if _bobber_audio == null or _bobber_audio.stream == null: - return - _bobber_audio.play() - - -func _stop_fight_audio() -> void: - if _fight_audio != null and _fight_audio.playing: - _fight_audio.stop() - - -func _configure_audio_loop(stream: AudioStreamWAV) -> void: - stream.loop_mode = AudioStreamWAV.LOOP_FORWARD - if stream.loop_end <= stream.loop_begin: - stream.loop_begin = 0 - stream.loop_end = maxi( - 1, - roundi(stream.get_length() * float(stream.mix_rate)), - ) - - -func _start_reeling_audio() -> void: - if _reeling_audio == null or _reeling_audio.stream == null: - return - if not _reeling_audio.playing: - _reeling_audio.play() - - -func _stop_reeling_audio() -> void: - if _reeling_audio != null and _reeling_audio.playing: - _reeling_audio.stop() - - func resolve_safe_withdrawal_surface( from: Vector3, to: Vector3, diff --git a/fishing/fishing_spot.tscn b/fishing/fishing_spot.tscn index 09cf1ae..322f618 100644 --- a/fishing/fishing_spot.tscn +++ b/fishing/fishing_spot.tscn @@ -1,9 +1,6 @@ -[gd_scene load_steps=15 format=3] +[gd_scene load_steps=12 format=3] [ext_resource type="Script" path="res://fishing/fishing_spot.gd" id="1_spot"] -[ext_resource type="AudioStream" path="res://audio/sfx/fishing/fighting.wav" id="2_fighting_audio"] -[ext_resource type="AudioStream" path="res://audio/sfx/fishing/reeling.wav" id="2_reeling_audio"] -[ext_resource type="AudioStream" path="res://audio/sfx/fishing/bobber.wav" id="2_bobber_audio"] [ext_resource type="Script" path="res://fishing/fishing_presentation.gd" id="3_presentation"] [ext_resource type="Script" path="res://fishing/catch_controller.gd" id="4_catch"] @@ -44,24 +41,6 @@ size = Vector3(0.62, 0.04, 0.09) [node name="FishingSpot" type="Node3D"] script = ExtResource("1_spot") -[node name="BobberAudio" type="AudioStreamPlayer" parent="."] -unique_name_in_owner = true -stream = ExtResource("2_bobber_audio") -volume_db = -14.0 -bus = &"SFX" - -[node name="FightAudio" type="AudioStreamPlayer" parent="."] -unique_name_in_owner = true -stream = ExtResource("2_fighting_audio") -volume_db = -10.0 -bus = &"SFX" - -[node name="ReelingAudio" type="AudioStreamPlayer" parent="."] -unique_name_in_owner = true -stream = ExtResource("2_reeling_audio") -volume_db = -10.0 -bus = &"SFX" - [node name="CatchController" type="Node" parent="."] unique_name_in_owner = true script = ExtResource("4_catch") diff --git a/main/main.gd b/main/main.gd index 059d0b1..8b14388 100644 --- a/main/main.gd +++ b/main/main.gd @@ -201,15 +201,9 @@ var _application_initialized := false var _pending_existing_root_path := "" var _local_recovery_attempt_id: String = "" -@onready var _shoreline_ambience: ShorelineAmbience = %ShorelineAmbience - func _ready() -> void: DisplayServer.window_set_title("NETfishing") - _shoreline_ambience.configure( - _player, - _test_world.get_saltwater_shoreline_mesh(), - ) var menu_pattern_material := ( _player_menu_backdrop.material as ShaderMaterial ) @@ -1032,7 +1026,6 @@ func _reset_pixelation() -> void: func _set_gameplay_active(active: bool) -> void: _gameplay_started = active - _shoreline_ambience.set_active(active) _title_background.visible = not active _world_pixelation.set_gameplay_active(active) _ui_pixelation.set_gameplay_active(active) diff --git a/main/main.tscn b/main/main.tscn index 8f66df1..03a38ab 100644 --- a/main/main.tscn +++ b/main/main.tscn @@ -53,8 +53,6 @@ [ext_resource type="Script" path="res://network/network_world_weather_service.gd" id="51_network_world_weather"] [ext_resource type="Script" path="res://jobs/player_job_service.gd" id="52_player_jobs"] [ext_resource type="Script" path="res://network/network_job_service.gd" id="53_network_jobs"] -[ext_resource type="Script" path="res://world/shoreline_ambience.gd" id="54_shoreline_ambience"] -[ext_resource type="AudioStream" path="res://audio/ambience/waves.wav" id="55_waves"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water_native"] shader = ExtResource("40_title_water") @@ -279,15 +277,6 @@ stream = ExtResource("13_title_music") volume_db = -80.0 bus = &"Music" -[node name="ShorelineAmbience" type="Node" parent="."] -unique_name_in_owner = true -script = ExtResource("54_shoreline_ambience") - -[node name="WavesAudio" type="AudioStreamPlayer" parent="ShorelineAmbience"] -unique_name_in_owner = true -stream = ExtResource("55_waves") -bus = &"SFX" - [node name="WorldPixelationPostprocess" parent="." unique_id=344378000 instance=ExtResource("16_world_pixelation")] unique_name_in_owner = true diff --git a/player/player.gd b/player/player.gd index 99a8e65..08c4217 100644 --- a/player/player.gd +++ b/player/player.gd @@ -94,8 +94,6 @@ class ShowcaseCameraSnapshot: @export var maximum_zoom: float = 8.0 @export var zoom_step: float = 0.75 @export var zoom_smoothing: float = 12.0 -@export_range(0.1, 12.0, 0.1) var controller_zoom_speed: float = 4.0 -@export_range(0.0, 1.0, 0.01) var controller_trigger_threshold: float = 0.55 @onready var _visuals: Node3D = %Visuals @onready var _character_animation_player: AnimationPlayer = ( @@ -292,26 +290,16 @@ func _process(delta: float) -> void: Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y) ) if stick.length() > controller_camera_deadzone: - if ( - Input.get_joy_axis(0, JOY_AXIS_TRIGGER_RIGHT) - >= controller_trigger_threshold - ): - var vertical_zoom_input: float = _apply_axis_deadzone(stick.y) - _set_target_zoom( - _target_zoom - + vertical_zoom_input * controller_zoom_speed * delta - ) - else: - var adjusted_strength: float = ( - (stick.length() - controller_camera_deadzone) - / (1.0 - controller_camera_deadzone) - ) - _rotate_camera( - stick.normalized() - * adjusted_strength - * controller_camera_speed - * delta - ) + var adjusted_strength: float = ( + (stick.length() - controller_camera_deadzone) + / (1.0 - controller_camera_deadzone) + ) + _rotate_camera( + stick.normalized() + * adjusted_strength + * controller_camera_speed + * delta + ) var zoom_weight: float = 1.0 - exp(-zoom_smoothing * delta) _spring_arm.spring_length = lerpf( @@ -447,17 +435,6 @@ func _set_target_zoom(value: float) -> void: _target_zoom = clampf(value, minimum_zoom, maximum_zoom) -func _apply_axis_deadzone(value: float) -> float: - var magnitude: float = absf(value) - if magnitude <= controller_camera_deadzone: - return 0.0 - return ( - signf(value) - * (magnitude - controller_camera_deadzone) - / (1.0 - controller_camera_deadzone) - ) - - func set_local_control(enabled: bool) -> void: local_control_enabled = enabled if is_node_ready(): diff --git a/project.godot b/project.godot index 9ec4067..9c0fd9a 100644 --- a/project.godot +++ b/project.godot @@ -80,13 +80,13 @@ slow_walk={ interact={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) -, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":3,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null) ] } fish_primary={ "deadzone": 0.2, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null) -, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":10,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":5,"axis_value":1.0,"script":null) ] } camera_drag={ @@ -97,11 +97,13 @@ camera_drag={ camera_zoom_in={ "deadzone": 0.2, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":10,"pressure":0.0,"pressed":false,"script":null) ] } camera_zoom_out={ "deadzone": 0.2, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":9,"pressure":0.0,"pressed":false,"script":null) ] } hotbar_1={ @@ -176,16 +178,6 @@ open_emotes={ , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null) ] } -open_quick_actions={ -"deadzone": 0.2, -"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null) -] -} -open_chat={ -"deadzone": 0.2, -"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":9,"pressure":0.0,"pressed":false,"script":null) -] -} open_tacklebox={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) @@ -221,20 +213,6 @@ alternate_fishing={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":92,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } -ui_accept={ -"deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) -, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) -, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) -, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) -] -} -ui_cancel={ -"deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) -, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null) -] -} [physics] diff --git a/scripts/run_validations.sh b/scripts/run_validations.sh deleted file mode 100755 index 1fa7312..0000000 --- a/scripts/run_validations.sh +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" -readonly GODOT_BIN="${GODOT_BIN:-godot}" -readonly TEST_TIMEOUT_SECONDS="${TEST_TIMEOUT_SECONDS:-120}" -readonly RUN_ROOT="$(mktemp -d -t netfishing-validations.XXXXXX)" - -readonly -a QUICK_TESTS=( - "tests/android_readiness_validation.gd" - "tests/fish_catalog_content_validation.gd" - "tests/fish_quality_validation.gd" - "tests/fishing_audio_validation.gd" - "tests/fishing_surface_validation.gd" - "tests/logbook_validation.gd" - "tests/player_experience_validation.gd" - "tests/shoreline_ambience_validation.gd" - "tests/surface_drawing_validation.gd" - "tests/terrain_projection_validation.gd" - "tests/world_time_validation.gd" - "tests/world_weather_validation.gd" -) - -readonly -a RUNTIME_TESTS=( - "tests/inventory_notepad_art_validation.gd" - "tests/logbook_runtime_validation.gd" - "tests/player_experience_ui_validation.gd" - "tests/ui_scaling_runtime_validation.gd" -) - -readonly -a HOST_TESTS=( - "tests/art_tools_validation.gd" - "tests/economy_regression_validation.gd" - "tests/fish_hotbar_showcase_validation.gd" - "tests/fishing_authority_validation.gd" - "tests/job_system_validation.gd" - "tests/surface_drawing_runtime_validation.gd" -) - -readonly -a NETWORK_TESTS=( - "tests/economy_regression_validation.gd" - "tests/fish_showcase_multiplayer_validation.gd" - "tests/fishing_multiplayer_validation.gd" - "tests/job_multiplayer_validation.gd" - "tests/surface_drawing_multiplayer_validation.gd" - "tests/world_time_multiplayer_validation.gd" -) - -cleanup() { - rm -rf -- "${RUN_ROOT}" -} -trap cleanup EXIT INT TERM - -usage() { - printf 'Usage: %s {quick|full|host|network|all|--list}\n' "$0" -} - -prepare_root() { - local name="$1" - local root="${RUN_ROOT}/${name}" - mkdir -p -- "${root}/data" "${root}/config" "${root}/cache" - printf '%s\n' "${root}" -} - -run_test() { - local script="$1" - local name="${script#tests/}" - name="${name%.gd}" - local root - root="$(prepare_root "${name}")" - printf '\n==> %s\n' "${script}" - XDG_DATA_HOME="${root}/data" \ - XDG_CONFIG_HOME="${root}/config" \ - XDG_CACHE_HOME="${root}/cache" \ - timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \ - --headless --path "${PROJECT_ROOT}" --script "${script}" -} - -run_network_test() { - local script="$1" - local name="${script#tests/}" - name="${name%.gd}" - local host_root client_root host_pid host_status client_status - host_root="$(prepare_root "${name}-host")" - client_root="$(prepare_root "${name}-client")" - printf '\n==> %s (host + client)\n' "${script}" - XDG_DATA_HOME="${host_root}/data" \ - XDG_CONFIG_HOME="${host_root}/config" \ - XDG_CACHE_HOME="${host_root}/cache" \ - timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \ - --headless --path "${PROJECT_ROOT}" --script "${script}" -- host \ - >"${host_root}/output.log" 2>&1 & - host_pid=$! - sleep 0.75 - set +e - XDG_DATA_HOME="${client_root}/data" \ - XDG_CONFIG_HOME="${client_root}/config" \ - XDG_CACHE_HOME="${client_root}/cache" \ - timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \ - --headless --path "${PROJECT_ROOT}" --script "${script}" -- client \ - >"${client_root}/output.log" 2>&1 - client_status=$? - wait "${host_pid}" - host_status=$? - set -e - printf '%s\n' '-- host output --' - sed -n '1,240p' "${host_root}/output.log" - printf '%s\n' '-- client output --' - sed -n '1,240p' "${client_root}/output.log" - if ((host_status != 0 || client_status != 0)); then - printf 'error: host exited %d; client exited %d\n' \ - "${host_status}" "${client_status}" >&2 - return 1 - fi -} - -run_quick() { - local test_script - for test_script in "${QUICK_TESTS[@]}"; do - run_test "${test_script}" - done -} - -run_full() { - local test_script - run_quick - for test_script in "${RUNTIME_TESTS[@]}"; do - run_test "${test_script}" - done -} - -run_host() { - local test_script - for test_script in "${HOST_TESTS[@]}"; do - run_test "${test_script}" - done -} - -run_network() { - local test_script - for test_script in "${NETWORK_TESTS[@]}"; do - run_network_test "${test_script}" - done -} - -list_tests() { - printf '%s\n' 'Quick tests:' - printf ' %s\n' "${QUICK_TESTS[@]}" - printf '%s\n' 'Additional full-suite tests:' - printf ' %s\n' "${RUNTIME_TESTS[@]}" - printf '%s\n' 'Single-process tests requiring a local UDP bind:' - printf ' %s\n' "${HOST_TESTS[@]}" - printf '%s\n' 'Paired network tests:' - printf ' %s\n' "${NETWORK_TESTS[@]}" -} - -case "${1:-}" in - quick) - run_quick - ;; - full) - run_full - ;; - host) - run_host - ;; - network) - run_network - ;; - all) - run_full - run_host - run_network - ;; - --list) - list_tests - ;; - *) - usage >&2 - exit 2 - ;; -esac - -printf '\nAll requested validations passed.\n' diff --git a/tests/android_readiness_validation.gd b/tests/android_readiness_validation.gd index 480fcce..5a03dc5 100644 --- a/tests/android_readiness_validation.gd +++ b/tests/android_readiness_validation.gd @@ -15,30 +15,16 @@ func _init() -> void: assert(_has_joypad_motion(&"move_left", JOY_AXIS_LEFT_X, -1.0)) assert(_has_joypad_motion(&"move_right", JOY_AXIS_LEFT_X, 1.0)) assert(_has_joypad_button(&"jump", JOY_BUTTON_A)) - assert(_has_joypad_button(&"ui_accept", JOY_BUTTON_A)) - assert(_has_joypad_button(&"ui_cancel", JOY_BUTTON_B)) - assert(_has_joypad_button(&"interact", JOY_BUTTON_Y)) - assert(_has_joypad_button(&"fish_primary", JOY_BUTTON_RIGHT_SHOULDER)) - assert(not _has_joypad_motion( - &"fish_primary", JOY_AXIS_TRIGGER_LEFT, 1.0 - )) - assert(not _has_joypad_motion( - &"fish_primary", JOY_AXIS_TRIGGER_RIGHT, 1.0 - )) + assert(_has_joypad_button(&"interact", JOY_BUTTON_X)) + assert(_has_joypad_motion(&"fish_primary", JOY_AXIS_TRIGGER_RIGHT, 1.0)) assert(_has_joypad_button(&"sprint", JOY_BUTTON_LEFT_STICK)) - assert(not _has_joypad_button( - &"camera_zoom_out", JOY_BUTTON_LEFT_SHOULDER - )) - assert(not _has_joypad_button( - &"camera_zoom_in", JOY_BUTTON_RIGHT_SHOULDER - )) + assert(_has_joypad_button(&"camera_zoom_out", JOY_BUTTON_LEFT_SHOULDER)) + assert(_has_joypad_button(&"camera_zoom_in", JOY_BUTTON_RIGHT_SHOULDER)) assert(_has_joypad_button(&"hotbar_previous", JOY_BUTTON_DPAD_LEFT)) assert(_has_joypad_button(&"hotbar_next", JOY_BUTTON_DPAD_RIGHT)) assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_BACK)) assert(_has_joypad_button(&"open_system_menu", JOY_BUTTON_START)) assert(_has_joypad_button(&"open_emotes", JOY_BUTTON_DPAD_UP)) - assert(_has_joypad_button(&"open_quick_actions", JOY_BUTTON_DPAD_DOWN)) - assert(_has_joypad_button(&"open_chat", JOY_BUTTON_LEFT_SHOULDER)) print("android readiness validation passed") quit() diff --git a/tests/economy_regression_validation.gd b/tests/economy_regression_validation.gd index 51dca5d..0f54ca7 100644 --- a/tests/economy_regression_validation.gd +++ b/tests/economy_regression_validation.gd @@ -48,7 +48,7 @@ func _run() -> void: as PlayerAssetReservationService ) assert(player != null) - assert(catalog != null and catalog.candidates.size() == 19) + assert(catalog != null and catalog.candidates.size() == 8) assert(sale_service != null) assert(shop_service != null) assert(session != null and session.is_host()) diff --git a/tests/fish_catalog_content_validation.gd b/tests/fish_catalog_content_validation.gd index 59aaf3a..2a74663 100644 --- a/tests/fish_catalog_content_validation.gd +++ b/tests/fish_catalog_content_validation.gd @@ -40,22 +40,8 @@ const CATFISH_IDS: Array[StringName] = [ const FRESH_WATER_IDS: Array[StringName] = [ &"bluegill", &"carp", &"catfish_blue", &"catfish_channel", &"catfish_flathead", &"catfish_white", - &"goby_round", -] -const SALT_WATER_IDS: Array[StringName] = [ - &"bass", - &"sunfish", - &"tuna_albacore", - &"tuna_bigeye", - &"tuna_bluefin", - &"tuna_skipjack", - &"tuna_yellowfin", - &"salmon_atlantic", - &"salmon_chum", - &"salmon_coho", - &"salmon_pink", - &"salmon_sockeye", ] +const SALT_WATER_IDS: Array[StringName] = [&"bass", &"sunfish"] func _initialize() -> void: @@ -72,9 +58,9 @@ func _run() -> void: func _validate_catalog_and_pools() -> void: - assert(Catalog.candidates.size() == 19) - assert(PondPool.candidates.size() == 7) - assert(OceanPool.candidates.size() == 12) + assert(Catalog.candidates.size() == 8) + assert(PondPool.candidates.size() == 6) + assert(OceanPool.candidates.size() == 2) for fish_id: StringName in ORIGINAL_IDS: var original_fish: FishDataType = Catalog.get_fish_by_id(fish_id) assert(original_fish != null) @@ -118,43 +104,6 @@ func _validate_catalog_and_pools() -> void: assert(fish.sell_value_min == int(values[4])) assert(fish.sell_value_max == int(values[5])) - var expected_tuna_values: Dictionary[StringName, Array] = { - &"tuna_albacore": [2, 1.5, 10.0, 45.0, 12, 24], - &"tuna_bigeye": [3, 0.55, 20.0, 120.0, 22, 48], - &"tuna_bluefin": [4, 0.18, 30.0, 250.0, 35, 90], - &"tuna_skipjack": [1, 3.0, 5.0, 25.0, 8, 16], - &"tuna_yellowfin": [2, 1.0, 15.0, 80.0, 16, 36], - } - for fish_id: StringName in expected_tuna_values: - var fish: FishDataType = Catalog.get_fish_by_id(fish_id) - var values: Array = expected_tuna_values[fish_id] - assert(fish != null and fish.is_selectable()) - assert(int(fish.rarity) == int(values[0])) - assert(is_equal_approx(fish.base_catch_weight, float(values[1]))) - assert(is_equal_approx(fish.weight_min_lb, float(values[2]))) - assert(is_equal_approx(fish.weight_max_lb, float(values[3]))) - assert(fish.sell_value_min == int(values[4])) - assert(fish.sell_value_max == int(values[5])) - - var expected_new_values: Dictionary[StringName, Array] = { - &"goby_round": [0, 8.0, 0.1, 0.6, 2, 3], - &"salmon_atlantic": [3, 0.65, 8.0, 40.0, 20, 42], - &"salmon_chum": [1, 2.5, 6.0, 25.0, 10, 22], - &"salmon_coho": [2, 1.4, 5.0, 30.0, 14, 28], - &"salmon_pink": [1, 3.0, 3.0, 12.0, 8, 15], - &"salmon_sockeye": [2, 1.6, 4.0, 15.0, 12, 24], - } - for fish_id: StringName in expected_new_values: - var fish: FishDataType = Catalog.get_fish_by_id(fish_id) - var values: Array = expected_new_values[fish_id] - assert(fish != null and fish.is_selectable()) - assert(int(fish.rarity) == int(values[0])) - assert(is_equal_approx(fish.base_catch_weight, float(values[1]))) - assert(is_equal_approx(fish.weight_min_lb, float(values[2]))) - assert(is_equal_approx(fish.weight_max_lb, float(values[3]))) - assert(fish.sell_value_min == int(values[4])) - assert(fish.sell_value_max == int(values[5])) - var pond_context := FishingContextType.new() pond_context.location_tags = [&"starter_pond"] pond_context.water_type = WaterType.Type.FRESH_WATER diff --git a/tests/fishing_audio_validation.gd b/tests/fishing_audio_validation.gd deleted file mode 100644 index 02a59eb..0000000 --- a/tests/fishing_audio_validation.gd +++ /dev/null @@ -1,54 +0,0 @@ -extends SceneTree - -const FishingSpotScene := preload("res://fishing/fishing_spot.tscn") - - -func _initialize() -> void: - call_deferred("_run") - - -func _run() -> void: - var fishing_spot := FishingSpotScene.instantiate() as FishingSpot - root.add_child(fishing_spot) - await process_frame - - var fight_audio := fishing_spot.get_node("%FightAudio") as AudioStreamPlayer - var bobber_audio := fishing_spot.get_node( - "%BobberAudio" - ) as AudioStreamPlayer - assert(bobber_audio != null) - assert(bobber_audio.stream != null) - assert(bobber_audio.bus == &"SFX") - assert(is_equal_approx(bobber_audio.volume_db, -14.0)) - var bobber_stream := bobber_audio.stream as AudioStreamWAV - assert(bobber_stream != null) - assert(bobber_stream.loop_mode == AudioStreamWAV.LOOP_DISABLED) - assert(fight_audio != null) - assert(fight_audio.stream != null) - assert(fight_audio.bus == &"SFX") - assert(is_equal_approx(fight_audio.volume_db, -10.0)) - var fight_stream := fight_audio.stream as AudioStreamWAV - assert(fight_stream != null) - assert(fight_stream.loop_mode == AudioStreamWAV.LOOP_FORWARD) - assert(fight_stream.loop_end > fight_stream.loop_begin) - var reeling_audio := fishing_spot.get_node( - "%ReelingAudio" - ) as AudioStreamPlayer - assert(reeling_audio != null) - assert(reeling_audio.stream != null) - assert(reeling_audio.bus == &"SFX") - assert(is_equal_approx(reeling_audio.volume_db, -10.0)) - var reeling_stream := reeling_audio.stream as AudioStreamWAV - assert(reeling_stream != null) - assert(reeling_stream.loop_mode == AudioStreamWAV.LOOP_FORWARD) - assert(reeling_stream.loop_end > reeling_stream.loop_begin) - - assert(fishing_spot.has_method("_start_fight_audio")) - assert(fishing_spot.has_method("_play_bobber_audio")) - assert(fishing_spot.has_method("_stop_fight_audio")) - assert(fishing_spot.has_method("_start_reeling_audio")) - assert(fishing_spot.has_method("_stop_reeling_audio")) - fishing_spot.free() - await process_frame - print("Fishing audio validation: PASS") - quit() diff --git a/tests/fishing_audio_validation.gd.uid b/tests/fishing_audio_validation.gd.uid deleted file mode 100644 index e9cd6d7..0000000 --- a/tests/fishing_audio_validation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bby8mv7bsjd3w diff --git a/tests/logbook_runtime_validation.gd b/tests/logbook_runtime_validation.gd index 923bbf1..b201b9a 100644 --- a/tests/logbook_runtime_validation.gd +++ b/tests/logbook_runtime_validation.gd @@ -49,20 +49,20 @@ func _run() -> void: assert(not hotbar.visible) var entry_buttons: Dictionary = logbook.get("_entry_buttons") - assert(entry_buttons.size() == 7) + assert(entry_buttons.size() == 6) await _capture_if_requested("-unknown") logbook.call( "_select_category", WaterType.Type.FRESH_WATER ) await create_timer(0.25).timeout - assert((logbook.get("_entry_buttons") as Dictionary).size() == 7) + assert((logbook.get("_entry_buttons") as Dictionary).size() == 6) await _capture_if_requested("-fresh") logbook.call("_select_category", WaterType.Type.SALT_WATER) await create_timer(0.25).timeout - assert((logbook.get("_entry_buttons") as Dictionary).size() == 12) + assert((logbook.get("_entry_buttons") as Dictionary).size() == 2) logbook.call("_select_category", WaterType.Type.FRESH_WATER) await create_timer(0.25).timeout - assert((logbook.get("_entry_buttons") as Dictionary).size() == 7) + assert((logbook.get("_entry_buttons") as Dictionary).size() == 6) player.collection_log.mark_discovered(&"bluegill") await process_frame logbook.call("_select_entry", &"bluegill", &"bluegill") @@ -101,7 +101,7 @@ func _validate_save_round_trip( var player := main.get("_player") as Player var catalog := main.get("fish_catalog") as FishPool assert(catalog != null) - assert(catalog.candidates.size() == 19) + assert(catalog.candidates.size() == 8) for index: int in 4: _add_test_catch(player, catalog.candidates[index]) assert(save_manager.save_now()) @@ -122,7 +122,7 @@ func _validate_save_round_trip( assert(player.inventory.replace_all_catches(no_catches, 1)) assert(player.collection_log.replace_discovered_ids(no_discoveries)) assert(save_manager.load_player_data()) - assert(player.inventory.get_all_catches().size() == 19) + assert(player.inventory.get_all_catches().size() == 8) for fish: FishData in catalog.candidates: assert(player.inventory.get_count(fish.id) == 1) assert(player.collection_log.has_discovered(fish.id)) diff --git a/tests/logbook_validation.gd b/tests/logbook_validation.gd index 8003fa4..4c25e35 100644 --- a/tests/logbook_validation.gd +++ b/tests/logbook_validation.gd @@ -49,17 +49,6 @@ func _validate_catalog() -> void: &"catfish_channel", &"catfish_flathead", &"catfish_white", - &"tuna_albacore", - &"tuna_bigeye", - &"tuna_bluefin", - &"tuna_skipjack", - &"tuna_yellowfin", - &"goby_round", - &"salmon_atlantic", - &"salmon_chum", - &"salmon_coho", - &"salmon_pink", - &"salmon_sockeye", ] assert(LogbookCatalog.CATALOG_ORDER == expected_ids) for index: int in expected_ids.size(): @@ -73,20 +62,7 @@ func _validate_catalog() -> void: ) var expected_category: WaterType.Type = ( WaterType.Type.SALT_WATER - if expected_ids[index] in [ - &"bass", - &"sunfish", - &"tuna_albacore", - &"tuna_bigeye", - &"tuna_bluefin", - &"tuna_skipjack", - &"tuna_yellowfin", - &"salmon_atlantic", - &"salmon_chum", - &"salmon_coho", - &"salmon_pink", - &"salmon_sockeye", - ] + if expected_ids[index] in [&"bass", &"sunfish"] else WaterType.Type.FRESH_WATER ) assert( @@ -129,7 +105,7 @@ func _validate_page() -> void: page.call("_select_category", category) await create_timer(0.25).timeout var entries: Dictionary = page.get("_entry_buttons") - assert(entries.size() == (7 if category == WaterType.Type.FRESH_WATER else 12)) + assert(entries.size() == (6 if category == WaterType.Type.FRESH_WATER else 2)) for fish: FishDataType in LogbookCatalog.ordered_species( CatalogResource.candidates ): @@ -179,7 +155,7 @@ func _validate_page() -> void: candidate.display_name ) ) - assert(silhouette_count == 19) + assert(silhouette_count == 8) page.call("_select_category", WaterType.Type.OTHER) await create_timer(0.25).timeout diff --git a/tests/shoreline_ambience_validation.gd b/tests/shoreline_ambience_validation.gd deleted file mode 100644 index 505452a..0000000 --- a/tests/shoreline_ambience_validation.gd +++ /dev/null @@ -1,48 +0,0 @@ -extends SceneTree - -const ShorelineAmbienceType := preload("res://world/shoreline_ambience.gd") -const WavesStream := preload("res://audio/ambience/waves.wav") - - -func _initialize() -> void: - call_deferred("_run") - - -func _run() -> void: - var waves := WavesStream as AudioStreamWAV - assert(waves != null) - - var segments: Array[PackedVector2Array] = [ - PackedVector2Array([Vector2.ZERO, Vector2(10.0, 0.0)]), - ] - assert(is_equal_approx( - ShorelineAmbienceType.distance_to_segments(Vector2(5.0, 3.0), segments), - 3.0, - )) - assert(is_equal_approx( - ShorelineAmbienceType.distance_to_segments(Vector2(-4.0, 0.0), segments), - 4.0, - )) - - var controller := ShorelineAmbienceType.new() as ShorelineAmbience - var runtime_audio := AudioStreamPlayer.new() - runtime_audio.name = "WavesAudio" - runtime_audio.unique_name_in_owner = true - runtime_audio.stream = WavesStream - runtime_audio.bus = &"SFX" - controller.add_child(runtime_audio) - runtime_audio.owner = controller - root.add_child(controller) - await process_frame - assert(runtime_audio.bus == &"SFX") - assert(controller.near_distance < controller.far_distance) - assert(controller.near_volume_db > controller.far_volume_db) - var runtime_waves := runtime_audio.stream as AudioStreamWAV - assert(runtime_waves.loop_mode == AudioStreamWAV.LOOP_FORWARD) - assert(runtime_waves.loop_begin == 0) - assert(runtime_waves.loop_end == 1044956) - controller.free() - await process_frame - - print("Shoreline ambience validation: PASS") - quit() diff --git a/tests/shoreline_ambience_validation.gd.uid b/tests/shoreline_ambience_validation.gd.uid deleted file mode 100644 index 4b7987b..0000000 --- a/tests/shoreline_ambience_validation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwvhgpbkb00l1 diff --git a/tests/world_time_validation.gd b/tests/world_time_validation.gd index 1fed6e7..a5fde90 100644 --- a/tests/world_time_validation.gd +++ b/tests/world_time_validation.gd @@ -17,12 +17,6 @@ const FishableWaterRegionType = preload( const WeatherIconType = preload("res://ui/weather_icon.gd") const Catalog: FishPoolType = preload("res://fish/pools/fish_catalog.tres") -const SaltWaterMaterial: ShaderMaterial = preload( - "res://world/materials/stylized_water.tres" -) -const FreshWaterMaterial: ShaderMaterial = preload( - "res://world/materials/stylized_water_fresh.tres" -) func _initialize() -> void: @@ -144,21 +138,7 @@ func _validate_fishing_availability() -> void: assert(not night_fish.availability.is_available(day_context)) assert(night_fish.availability.is_available(night_context)) assert(night_fish.availability.is_available(transition_context)) - for fish_id: StringName in [ - &"bass", - &"carp", - &"tuna_albacore", - &"tuna_bigeye", - &"tuna_bluefin", - &"tuna_skipjack", - &"tuna_yellowfin", - &"goby_round", - &"salmon_atlantic", - &"salmon_chum", - &"salmon_coho", - &"salmon_pink", - &"salmon_sockeye", - ]: + for fish_id: StringName in [&"bass", &"carp"]: var all_time_fish: FishDataType = Catalog.get_fish_by_id(fish_id) assert(all_time_fish.availability.is_available(day_context)) assert(all_time_fish.availability.is_available(night_context)) @@ -249,14 +229,6 @@ func _validate_environment_presentation() -> void: < 0.01 ) var day_ambient_energy: float = runtime_environment.ambient_light_energy - var day_water_brightness := float( - SaltWaterMaterial.get_shader_parameter("environment_brightness") - ) - assert(day_water_brightness > 0.99) - assert(is_equal_approx( - float(FreshWaterMaterial.get_shader_parameter("environment_brightness")), - day_water_brightness, - )) visuals.apply_time_immediately(0.0) var night_horizon: Color = runtime_sky_material.get_shader_parameter( "sky_horizon_color" @@ -279,47 +251,6 @@ func _validate_environment_presentation() -> void: assert(night_moon_direction.y > 0.85) assert(night_moon_direction.is_equal_approx(-night_sun_direction)) assert(runtime_environment.ambient_light_energy < day_ambient_energy) - var night_water_brightness := float( - SaltWaterMaterial.get_shader_parameter("environment_brightness") - ) - assert(night_water_brightness < day_water_brightness * 0.4) - assert(is_equal_approx( - float(FreshWaterMaterial.get_shader_parameter("environment_brightness")), - night_water_brightness, - )) - var night_water_tint := ( - SaltWaterMaterial.get_shader_parameter("environment_tint") as Color - ) - assert(night_water_tint.get_luminance() < 0.5) - var night_background_energy := runtime_environment.background_energy_multiplier - var night_adjustment_brightness := runtime_environment.adjustment_brightness - var night_adjustment_saturation := runtime_environment.adjustment_saturation - visuals.apply_weather_immediately(WorldWeatherService.Weather.FOGGY) - visuals.apply_time_immediately(0.0) - var foggy_sky_horizon := ( - runtime_sky_material.get_shader_parameter("sky_horizon_color") as Color - ) - assert(foggy_sky_horizon.is_equal_approx(night_horizon)) - assert(is_zero_approx(runtime_environment.fog_sky_affect)) - assert(is_equal_approx(runtime_environment.fog_depth_begin, 3.0)) - assert(is_equal_approx(runtime_environment.fog_depth_end, 28.0)) - assert(is_equal_approx( - float(SaltWaterMaterial.get_shader_parameter("environment_brightness")), - night_water_brightness, - )) - assert(is_equal_approx( - runtime_environment.background_energy_multiplier, - night_background_energy, - )) - assert(is_equal_approx( - runtime_environment.adjustment_brightness, - night_adjustment_brightness, - )) - assert(is_equal_approx( - runtime_environment.adjustment_saturation, - night_adjustment_saturation, - )) - visuals.apply_weather_immediately(WorldWeatherService.Weather.SUNNY) visuals.apply_time_immediately(20.0) var dusk_horizon: Color = runtime_sky_material.get_shader_parameter( "sky_horizon_color" diff --git a/tests/world_weather_validation.gd b/tests/world_weather_validation.gd index 1035a09..a5838f8 100644 --- a/tests/world_weather_validation.gd +++ b/tests/world_weather_validation.gd @@ -217,19 +217,15 @@ func _validate_weather_presentation() -> void: visuals.setup( clock, world_environment, sun, weather, rain_target ) - var runtime_environment: Environment = world_environment.environment - var clear_saturation: float = runtime_environment.adjustment_saturation visuals.apply_weather_immediately( WorldWeatherServiceType.Weather.FOGGY ) + var runtime_environment: Environment = world_environment.environment assert(runtime_environment.fog_depth_begin <= 4.01) assert(runtime_environment.fog_depth_end <= 42.01) - assert(is_zero_approx(runtime_environment.fog_sky_affect)) + assert(runtime_environment.fog_sky_affect >= 0.93) assert(runtime_environment.fog_aerial_perspective >= 0.91) - assert(is_equal_approx( - runtime_environment.adjustment_saturation, - clear_saturation, - )) + assert(runtime_environment.adjustment_saturation < 0.70) visuals.apply_weather_immediately( WorldWeatherServiceType.Weather.RAINY ) diff --git a/ui/chat_ui.gd b/ui/chat_ui.gd index 58b7c81..9167a18 100644 --- a/ui/chat_ui.gd +++ b/ui/chat_ui.gd @@ -194,13 +194,6 @@ func close_chat() -> void: func _unhandled_input(event: InputEvent) -> void: - if event.is_action_pressed("open_chat"): - if _opened: - close_chat() - elif _available: - open_chat() - get_viewport().set_input_as_handled() - return if event is InputEventKey and event.pressed and not event.echo: if event.keycode in [KEY_ENTER, KEY_KP_ENTER]: if _opened: diff --git a/ui/controller_virtual_cursor.gd b/ui/controller_virtual_cursor.gd deleted file mode 100644 index f56bb3e..0000000 --- a/ui/controller_virtual_cursor.gd +++ /dev/null @@ -1,40 +0,0 @@ -class_name ControllerVirtualCursor -extends Control - -const CURSOR_SIZE: Vector2 = Vector2(28.0, 28.0) -const OUTER_COLOR: Color = Color(0.02, 0.10, 0.14, 0.96) -const INNER_COLOR: Color = Color(0.34, 0.86, 0.91, 1.0) -const CENTER_COLOR: Color = Color(0.96, 1.0, 1.0, 1.0) - - -func _ready() -> void: - size = CURSOR_SIZE - mouse_filter = Control.MOUSE_FILTER_IGNORE - focus_mode = Control.FOCUS_NONE - visible = false - queue_redraw() - - -func set_pointer_position(pointer_position: Vector2) -> void: - position = pointer_position - CURSOR_SIZE * 0.5 - - -func _draw() -> void: - var center: Vector2 = CURSOR_SIZE * 0.5 - draw_circle(center, 8.0, OUTER_COLOR) - draw_circle(center, 5.0, INNER_COLOR) - draw_circle(center, 1.75, CENTER_COLOR) - draw_line(Vector2(center.x, 0.0), Vector2(center.x, 6.0), CENTER_COLOR, 2.0) - draw_line( - Vector2(center.x, CURSOR_SIZE.y - 6.0), - Vector2(center.x, CURSOR_SIZE.y), - CENTER_COLOR, - 2.0, - ) - draw_line(Vector2(0.0, center.y), Vector2(6.0, center.y), CENTER_COLOR, 2.0) - draw_line( - Vector2(CURSOR_SIZE.x - 6.0, center.y), - Vector2(CURSOR_SIZE.x, center.y), - CENTER_COLOR, - 2.0, - ) diff --git a/ui/controller_virtual_cursor.gd.uid b/ui/controller_virtual_cursor.gd.uid deleted file mode 100644 index 309a5c4..0000000 --- a/ui/controller_virtual_cursor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dehegl7ccn057 diff --git a/ui/emote_radial_menu.gd b/ui/emote_radial_menu.gd index e0c35de..3ff0622 100644 --- a/ui/emote_radial_menu.gd +++ b/ui/emote_radial_menu.gd @@ -13,12 +13,10 @@ const SECTOR_COUNT: int = 8 const SIT_SECTOR: int = 0 const RING_RADIUS: float = 172.0 const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0) -const CONTROLLER_SELECTION_DEADZONE: float = 0.35 var _buttons: Array[BubbleButton] = [] var _is_open: bool = false var _selected_sector: int = SIT_SECTOR -var _controller_selection_mode: bool = false func _ready() -> void: @@ -44,7 +42,7 @@ func handle_input(event: InputEvent, can_open: bool) -> bool: if event.is_pressed(): if _is_open or not can_open: return _is_open - open_menu(event is InputEventJoypadButton) + open_menu() return true if not _is_open: return false @@ -55,10 +53,9 @@ func handle_input(event: InputEvent, can_open: bool) -> bool: return true -func open_menu(controller_selection: bool = false) -> void: +func open_menu() -> void: _is_open = true _selected_sector = SIT_SECTOR - _controller_selection_mode = controller_selection visible = true _layout_bubbles() _apply_selection_styles() @@ -77,7 +74,7 @@ func _process(_delta: float) -> void: if not _is_open: return _layout_bubbles() - _update_selection() + _update_mouse_selection() func _layout_bubbles() -> void: @@ -91,27 +88,10 @@ func _layout_bubbles() -> void: bubble.pivot_offset = BUBBLE_SIZE * 0.5 -func _update_selection() -> void: - var stick: Vector2 = Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - if stick.length() >= CONTROLLER_SELECTION_DEADZONE: - _select_sector_from_offset(stick) - return - if _controller_selection_mode: - return - _update_mouse_selection() - - func _update_mouse_selection() -> void: var offset: Vector2 = get_local_mouse_position() - size * 0.5 if offset.length() < 24.0: return - _select_sector_from_offset(offset) - - -func _select_sector_from_offset(offset: Vector2) -> void: var angle: float = fposmod(offset.angle() + PI * 0.5 + PI / 8.0, TAU) var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT)))) if sector == _selected_sector: diff --git a/ui/game_ui.gd b/ui/game_ui.gd index 8b2b02d..16ad69d 100644 --- a/ui/game_ui.gd +++ b/ui/game_ui.gd @@ -34,10 +34,6 @@ const PlayerCoolerCapacityType = preload( ) const ChatUIType = preload("res://ui/chat_ui.gd") const EmoteRadialMenuType = preload("res://ui/emote_radial_menu.gd") -const QuickRadialMenuType = preload("res://ui/quick_radial_menu.gd") -const ControllerVirtualCursorType = preload( - "res://ui/controller_virtual_cursor.gd" -) const SurfaceDrawingToolbarType = preload( "res://ui/surface_drawing_toolbar.gd" ) @@ -62,11 +58,6 @@ signal passive_pointer_ui_changed(is_enabled: bool) signal player_menu_backdrop_visibility_changed(is_visible: bool) signal shop_backdrop_visibility_changed(is_visible: bool) -const VIRTUAL_MOUSE_INPUT_OWNER: StringName = &"controller_virtual_mouse" -const VIRTUAL_MOUSE_TRIGGER_THRESHOLD: float = 0.55 -const VIRTUAL_MOUSE_STICK_DEADZONE: float = 0.18 -const VIRTUAL_MOUSE_SPEED: float = 720.0 - @onready var _status_label: Label = %StatusLabel @onready var _gameplay_transient_hud: Control = %GameplayTransientHUD @onready var _experience_presentation: Control = %ExperiencePresentation @@ -86,7 +77,6 @@ const VIRTUAL_MOUSE_SPEED: float = 720.0 @onready var _experience_bubble: PanelContainer = %ExperienceBubble @onready var _experience_bubble_label: Label = %ExperienceBubbleLabel @onready var _canonical_stage: Control = %CanonicalStage -@onready var _ui_root: Control = %UIRoot @onready var _player_menu: PlayerMenuType = %PlayerMenu @onready var _screen_fade: ScreenFade = %ScreenFade @onready var _title_screen: TitleScreenType = %TitleScreen @@ -97,10 +87,6 @@ const VIRTUAL_MOUSE_SPEED: float = 720.0 @onready var _effect_status: Label = %EffectStatus @onready var _chat_ui: ChatUIType = %ChatUI @onready var _emote_radial_menu: EmoteRadialMenuType = %EmoteRadialMenu -@onready var _quick_radial_menu: QuickRadialMenuType = %QuickRadialMenu -@onready var _controller_virtual_cursor: ControllerVirtualCursorType = ( - %ControllerVirtualCursor -) @onready var _surface_drawing_toolbar: SurfaceDrawingToolbarType = ( %SurfaceDrawingToolbar ) @@ -129,15 +115,6 @@ var _experience_award_queue: Array[Dictionary] = [] var _experience_animation_active: bool = false var _experience_animation_generation: int = 0 var _experience_panel_rest_y: float = 18.0 -var _emote_prior_camera_input_enabled: bool = true -var _quick_prior_camera_input_enabled: bool = true -var _virtual_mouse_active: bool = false -var _virtual_mouse_prior_camera_input_enabled: bool = true -var _virtual_mouse_prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE -var _virtual_mouse_window_position: Vector2 = Vector2.ZERO -var _virtual_mouse_button_mask: int = 0 -var _virtual_mouse_right_pressed: bool = false -var _injecting_virtual_mouse_event: bool = false func _ready() -> void: @@ -151,7 +128,6 @@ func _ready() -> void: presentation_parent.get_child_count() - 1, ) _emote_radial_menu.emote_selected.connect(_on_emote_selected) - _quick_radial_menu.action_selected.connect(_on_quick_action_selected) _chat_ui.text_entry_ownership_changed.connect( _on_chat_text_entry_ownership_changed ) @@ -298,17 +274,6 @@ func setup( func _input(event: InputEvent) -> void: - if ( - _virtual_mouse_active - and _injecting_virtual_mouse_event - and event is InputEventMouseMotion - ): - _update_virtual_cursor_position( - (event as InputEventMouseMotion).position - ) - if _handle_virtual_mouse_input(event): - get_viewport().set_input_as_handled() - return if ( _surface_drawing_toolbar != null and _surface_drawing_toolbar.owns_pointer_event(event) @@ -330,7 +295,7 @@ func _input(event: InputEvent) -> void: ): get_viewport().set_input_as_handled() return - if _emote_radial_menu == null or _quick_radial_menu == null: + if _emote_radial_menu == null: return var can_open: bool = ( _gameplay_ui_enabled @@ -339,42 +304,8 @@ func _input(event: InputEvent) -> void: and not _shop_open and not _chat_input_open and not _showcase_active - and not _virtual_mouse_active ) - var emote_was_open: bool = _emote_radial_menu.is_open() - if _emote_radial_menu.handle_input( - event, - can_open and not _quick_radial_menu.is_open(), - ): - var emote_is_open: bool = _emote_radial_menu.is_open() - if emote_is_open != emote_was_open and _player != null: - if emote_is_open: - _emote_prior_camera_input_enabled = ( - _player.is_camera_input_enabled() - ) - _player.set_camera_input_enabled(false) - else: - _player.set_camera_input_enabled( - _emote_prior_camera_input_enabled - ) - get_viewport().set_input_as_handled() - return - var quick_was_open: bool = _quick_radial_menu.is_open() - if _quick_radial_menu.handle_input( - event, - can_open and not _emote_radial_menu.is_open(), - ): - var quick_is_open: bool = _quick_radial_menu.is_open() - if quick_is_open != quick_was_open and _player != null: - if quick_is_open: - _quick_prior_camera_input_enabled = ( - _player.is_camera_input_enabled() - ) - _player.set_camera_input_enabled(false) - else: - _player.set_camera_input_enabled( - _quick_prior_camera_input_enabled - ) + if _emote_radial_menu.handle_input(event, can_open): get_viewport().set_input_as_handled() @@ -383,212 +314,6 @@ func _on_emote_selected(emote_id: StringName) -> void: _player.toggle_sitting() -func _on_quick_action_selected(action_id: StringName) -> void: - match action_id: - &"stuff": - _player_menu.open_section(PlayerMenuType.Section.COOLER) - &"logbook": - _player_menu.open_section(PlayerMenuType.Section.LOGBOOK) - &"fishnet": - _player_menu.open_section(PlayerMenuType.Section.NET) - &"mail": - _player_menu.open_section(PlayerMenuType.Section.MAIL) - &"profile": - _player_menu.open_section(PlayerMenuType.Section.PROFILE) - &"online": - _player_menu.open_section(PlayerMenuType.Section.PLAYERS) - &"paint": - _toggle_surface_drawing() - &"chat": - _chat_ui.open_chat() - - -func _handle_virtual_mouse_input(event: InputEvent) -> bool: - var motion_event: InputEventJoypadMotion = event as InputEventJoypadMotion - if motion_event != null: - if motion_event.axis == JOY_AXIS_TRIGGER_LEFT: - var was_active: bool = _virtual_mouse_active - if motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD: - if not _virtual_mouse_active and _can_start_virtual_mouse(): - _begin_virtual_mouse() - elif _virtual_mouse_active: - _end_virtual_mouse() - return was_active or _virtual_mouse_active - if ( - _virtual_mouse_active - and motion_event.axis == JOY_AXIS_TRIGGER_RIGHT - ): - _set_virtual_mouse_button( - MOUSE_BUTTON_RIGHT, - motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, - ) - return true - var button_event: InputEventJoypadButton = event as InputEventJoypadButton - if ( - button_event != null - and button_event.button_index == JOY_BUTTON_RIGHT_SHOULDER - and ( - _virtual_mouse_active - or Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT) - >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD - ) - ): - if not _virtual_mouse_active and _can_start_virtual_mouse(): - _begin_virtual_mouse() - if _virtual_mouse_active: - _set_virtual_mouse_button(MOUSE_BUTTON_LEFT, button_event.pressed) - return true - return false - - -func _can_start_virtual_mouse() -> bool: - return ( - _gameplay_ui_enabled - and not _showcase_active - and _player != null - and _fishing_spot != null - and _fishing_spot.can_use_surface_drawing() - and not _emote_radial_menu.is_open() - and not _quick_radial_menu.is_open() - ) - - -func _begin_virtual_mouse() -> void: - if _virtual_mouse_active: - return - _virtual_mouse_active = true - _virtual_mouse_prior_camera_input_enabled = ( - _player.is_camera_input_enabled() - ) - _player.set_camera_input_enabled(false) - if _fishing_spot != null: - _fishing_spot.set_local_menu_input_suppressed( - VIRTUAL_MOUSE_INPUT_OWNER, - true, - ) - _virtual_mouse_prior_mouse_mode = Input.mouse_mode - Input.mouse_mode = Input.MOUSE_MODE_HIDDEN - _virtual_mouse_button_mask = 0 - _virtual_mouse_right_pressed = false - _virtual_mouse_window_position = Vector2(get_window().size) * 0.5 - _controller_virtual_cursor.visible = true - _emit_virtual_mouse_motion(Vector2.ZERO) - - -func _end_virtual_mouse() -> void: - if not _virtual_mouse_active: - return - if (_virtual_mouse_button_mask & MOUSE_BUTTON_MASK_LEFT) != 0: - _set_virtual_mouse_button(MOUSE_BUTTON_LEFT, false) - if _virtual_mouse_right_pressed: - _set_virtual_mouse_button(MOUSE_BUTTON_RIGHT, false) - _virtual_mouse_active = false - _controller_virtual_cursor.visible = false - if _fishing_spot != null: - _fishing_spot.set_local_menu_input_suppressed( - VIRTUAL_MOUSE_INPUT_OWNER, - false, - ) - if _player != null and is_instance_valid(_player): - _player.set_camera_input_enabled( - _virtual_mouse_prior_camera_input_enabled - ) - Input.mouse_mode = _virtual_mouse_prior_mouse_mode - - -func _update_virtual_mouse(delta: float) -> void: - if not _virtual_mouse_active: - return - if ( - Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT) - < VIRTUAL_MOUSE_TRIGGER_THRESHOLD - ): - _end_virtual_mouse() - return - var stick: Vector2 = Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - var stick_length: float = stick.length() - if stick_length <= VIRTUAL_MOUSE_STICK_DEADZONE: - return - var adjusted_strength: float = ( - (stick_length - VIRTUAL_MOUSE_STICK_DEADZONE) - / (1.0 - VIRTUAL_MOUSE_STICK_DEADZONE) - ) - var display_scale: float = UIReferencePresentationType.get_scale( - Vector2(get_window().size) - ) - var relative_motion: Vector2 = ( - stick.normalized() - * adjusted_strength - * VIRTUAL_MOUSE_SPEED - * display_scale - * delta - ) - var window_size: Vector2 = Vector2(get_window().size) - _virtual_mouse_window_position = Vector2( - clampf( - _virtual_mouse_window_position.x + relative_motion.x, - 0.0, - window_size.x, - ), - clampf( - _virtual_mouse_window_position.y + relative_motion.y, - 0.0, - window_size.y, - ), - ) - _emit_virtual_mouse_motion(relative_motion) - - -func _set_virtual_mouse_button(button: MouseButton, pressed: bool) -> void: - var mask: int = ( - MOUSE_BUTTON_MASK_LEFT - if button == MOUSE_BUTTON_LEFT - else MOUSE_BUTTON_MASK_RIGHT - ) - var already_pressed: bool = bool(_virtual_mouse_button_mask & mask) - if already_pressed == pressed: - return - if pressed: - _virtual_mouse_button_mask |= mask - else: - _virtual_mouse_button_mask &= ~mask - if button == MOUSE_BUTTON_RIGHT: - _virtual_mouse_right_pressed = pressed - var mouse_event := InputEventMouseButton.new() - mouse_event.position = _virtual_mouse_window_position - mouse_event.global_position = _virtual_mouse_window_position - mouse_event.button_index = button - mouse_event.button_mask = _virtual_mouse_button_mask - mouse_event.pressed = pressed - mouse_event.factor = 1.0 - _parse_virtual_mouse_event(mouse_event) - - -func _emit_virtual_mouse_motion(relative_motion: Vector2) -> void: - var motion_event := InputEventMouseMotion.new() - motion_event.position = _virtual_mouse_window_position - motion_event.global_position = _virtual_mouse_window_position - motion_event.relative = relative_motion - motion_event.button_mask = _virtual_mouse_button_mask - _parse_virtual_mouse_event(motion_event) - - -func _parse_virtual_mouse_event(event: InputEventMouse) -> void: - _injecting_virtual_mouse_event = true - Input.parse_input_event(event) - _injecting_virtual_mouse_event = false - - -func _update_virtual_cursor_position(viewport_position: Vector2) -> void: - var root_transform: Transform2D = _ui_root.get_global_transform_with_canvas() - _controller_virtual_cursor.set_pointer_position( - root_transform.affine_inverse() * viewport_position - ) - - func _toggle_surface_drawing() -> void: if _surface_drawing == null: return @@ -619,8 +344,7 @@ func setup_data_and_identity( ) -func _process(delta: float) -> void: - _update_virtual_mouse(delta) +func _process(_delta: float) -> void: _update_experience_bubble_position() if _item_effects == null or not _gameplay_ui_enabled: _effect_status.hide() @@ -679,19 +403,6 @@ func set_gameplay_ui_enabled(enabled: bool) -> void: _experience_presentation.visible = enabled _refresh_chat_availability() if not enabled: - _end_virtual_mouse() - if _emote_radial_menu != null and _emote_radial_menu.is_open(): - _emote_radial_menu.close_menu() - if _player != null: - _player.set_camera_input_enabled( - _emote_prior_camera_input_enabled - ) - if _quick_radial_menu != null and _quick_radial_menu.is_open(): - _quick_radial_menu.close_menu() - if _player != null: - _player.set_camera_input_enabled( - _quick_prior_camera_input_enabled - ) if _surface_drawing != null: _surface_drawing.deactivate() close_player_menu_for_session_end() diff --git a/ui/game_ui.tscn b/ui/game_ui.tscn index 0726da0..9d63e54 100644 --- a/ui/game_ui.tscn +++ b/ui/game_ui.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=21 format=3] +[gd_scene load_steps=19 format=3] [ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"] [ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"] @@ -11,8 +11,6 @@ [ext_resource type="Script" path="res://ui/chat_ui.gd" id="9_chat"] [ext_resource type="PackedScene" path="res://ui/emote_radial_menu.tscn" id="10_emote"] [ext_resource type="PackedScene" path="res://ui/surface_drawing_toolbar.tscn" id="11_drawing_toolbar"] -[ext_resource type="PackedScene" path="res://ui/quick_radial_menu.tscn" id="12_quick"] -[ext_resource type="Script" path="res://ui/controller_virtual_cursor.gd" id="13_cursor"] [sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"] bg_color = Color(0.032, 0.118, 0.15, 1) @@ -330,9 +328,6 @@ unique_name_in_owner = true [node name="EmoteRadialMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("10_emote")] unique_name_in_owner = true -[node name="QuickRadialMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("12_quick")] -unique_name_in_owner = true - [node name="ShopPrompt" type="PanelContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD"] unique_name_in_owner = true visible = false @@ -391,12 +386,6 @@ grow_vertical = 2 mouse_filter = 2 script = ExtResource("9_chat") -[node name="ControllerVirtualCursor" type="Control" parent="UIRoot"] -unique_name_in_owner = true -z_index = 500 -mouse_filter = 2 -script = ExtResource("13_cursor") - [node name="ScreenFade" type="ColorRect" parent="UIRoot"] unique_name_in_owner = true visible = false diff --git a/ui/logbook_catalog.gd b/ui/logbook_catalog.gd index 79c9df9..ad1a9c9 100644 --- a/ui/logbook_catalog.gd +++ b/ui/logbook_catalog.gd @@ -14,17 +14,6 @@ const CATALOG_ORDER: Array[StringName] = [ &"catfish_channel", &"catfish_flathead", &"catfish_white", - &"tuna_albacore", - &"tuna_bigeye", - &"tuna_bluefin", - &"tuna_skipjack", - &"tuna_yellowfin", - &"goby_round", - &"salmon_atlantic", - &"salmon_chum", - &"salmon_coho", - &"salmon_pink", - &"salmon_sockeye", ] # Short presentation notes are kept here with the catalog contract rather @@ -63,50 +52,6 @@ const FISH_FACTS: Dictionary[StringName, String] = { "white catfish began along the atlantic coast between new york " + "and florida. people later carried them far beyond that home range." ), - &"tuna_albacore": ( - "albacore have unusually long pectoral fins. their warm muscles help " - + "them cruise across wide stretches of open ocean." - ), - &"tuna_bigeye": ( - "bigeye tuna make daily trips between deep, cool water and warmer " - + "surface layers. their large eyes suit those dim depths." - ), - &"tuna_bluefin": ( - "bluefin tuna are powerful ocean travelers. heat retained in their " - + "swimming muscles lets them thrive in surprisingly cold seas." - ), - &"tuna_skipjack": ( - "skipjack travel in fast-moving schools and have dark stripes along " - + "their lower sides. they rarely stop swimming." - ), - &"tuna_yellowfin": ( - "yellowfin are named for their bright yellow fins and finlets. large " - + "schools often gather with other open-ocean hunters." - ), - &"goby_round": ( - "round gobies use fused pelvic fins like a suction cup to hold onto " - + "rocks. they are small fish with a famously large appetite." - ), - &"salmon_atlantic": ( - "atlantic salmon can return from the ocean to the river where they " - + "hatched. unlike many salmon, some survive to make the trip again." - ), - &"salmon_chum": ( - "chum salmon travel immense distances and develop striking bars when " - + "they return to fresh water to spawn." - ), - &"salmon_coho": ( - "coho salmon are agile hunters known for powerful leaps. young coho " - + "may spend more than a year growing in streams." - ), - &"salmon_pink": ( - "pink salmon usually follow a strict two-year life cycle. spawning " - + "males develop the hump that inspired their nickname." - ), - &"salmon_sockeye": ( - "sockeye salmon feed heavily on plankton at sea. adults turn vivid red " - + "as they return inland to spawn." - ), } static func category_for(fish: FishDataType) -> WaterType.Type: diff --git a/ui/player_menu.gd b/ui/player_menu.gd index d3ccfcf..af8148d 100644 --- a/ui/player_menu.gd +++ b/ui/player_menu.gd @@ -701,25 +701,6 @@ func open_menu() -> void: menu_visibility_changed.emit(true) -func open_section(section: Section) -> bool: - if ( - _shop_cooler_context_active - or _player == null - or _fishing_spot == null - or not _fishing_spot.can_open_player_menu() - ): - return false - if visible: - if _transitioning or _page_transitioning or _sale_confirmation.visible: - return false - if section != _current_section: - _show_section(section) - return true - _current_section = section - open_menu() - return visible - - func mount_shop_cooler( host: Control, buyer: FishBuyerProfileType, diff --git a/ui/quick_radial_menu.gd b/ui/quick_radial_menu.gd deleted file mode 100644 index 585bae2..0000000 --- a/ui/quick_radial_menu.gd +++ /dev/null @@ -1,152 +0,0 @@ -class_name QuickRadialMenu -extends Control - -signal action_selected(action_id: StringName) - -const BubbleButtonScene: PackedScene = preload( - "res://ui/components/bubble_menu/bubble_button.tscn" -) -const BubbleProfile: BubbleMenuProfile = preload( - "res://ui/components/bubble_menu/bubble_menu_profile.tres" -) -const SECTOR_COUNT: int = 8 -const RING_RADIUS: float = 172.0 -const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0) -const CONTROLLER_SELECTION_DEADZONE: float = 0.35 -const ACTIONS: Array[StringName] = [ - &"stuff", - &"logbook", - &"fishnet", - &"mail", - &"profile", - &"online", - &"paint", - &"chat", -] -const LABELS: Array[String] = [ - "stuff", - "logbook", - "fishnet", - "mail", - "profile", - "online", - "paint", - "chat", -] - -var _buttons: Array[BubbleButton] = [] -var _is_open: bool = false -var _selected_sector: int = 0 -var _controller_selection_mode: bool = false - - -func _ready() -> void: - visible = false - mouse_filter = Control.MOUSE_FILTER_IGNORE - for sector: int in SECTOR_COUNT: - var bubble: BubbleButton = BubbleButtonScene.instantiate() as BubbleButton - bubble.profile = BubbleProfile - bubble.focus_mode = Control.FOCUS_NONE - bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE - bubble.text = LABELS[sector] - add_child(bubble) - _buttons.append(bubble) - _apply_selection_styles() - - -func handle_input(event: InputEvent, can_open: bool) -> bool: - if not event.is_action("open_quick_actions"): - return false - var key_event: InputEventKey = event as InputEventKey - if key_event != null and key_event.echo: - return false - if event.is_pressed(): - if _is_open or not can_open: - return _is_open - open_menu(event is InputEventJoypadButton) - return true - if not _is_open: - return false - var selected: int = _selected_sector - close_menu() - call_deferred("_emit_selected_action", ACTIONS[selected]) - return true - - -func open_menu(controller_selection: bool = false) -> void: - _is_open = true - _selected_sector = 0 - _controller_selection_mode = controller_selection - visible = true - _layout_bubbles() - _apply_selection_styles() - - -func close_menu() -> void: - _is_open = false - visible = false - - -func is_open() -> bool: - return _is_open - - -func _emit_selected_action(action_id: StringName) -> void: - action_selected.emit(action_id) - - -func _process(_delta: float) -> void: - if not _is_open: - return - _layout_bubbles() - _update_selection() - - -func _layout_bubbles() -> void: - var center: Vector2 = size * 0.5 - for sector: int in SECTOR_COUNT: - var angle: float = -PI * 0.5 + TAU * float(sector) / float(SECTOR_COUNT) - var bubble_center: Vector2 = center + Vector2.from_angle(angle) * RING_RADIUS - var bubble: BubbleButton = _buttons[sector] - bubble.position = bubble_center - BUBBLE_SIZE * 0.5 - bubble.size = BUBBLE_SIZE - bubble.pivot_offset = BUBBLE_SIZE * 0.5 - - -func _update_selection() -> void: - var stick: Vector2 = Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - if stick.length() >= CONTROLLER_SELECTION_DEADZONE: - _select_sector_from_offset(stick) - return - if _controller_selection_mode: - return - _update_mouse_selection() - - -func _update_mouse_selection() -> void: - var offset: Vector2 = get_local_mouse_position() - size * 0.5 - if offset.length() < 24.0: - return - _select_sector_from_offset(offset) - - -func _select_sector_from_offset(offset: Vector2) -> void: - var angle: float = fposmod(offset.angle() + PI * 0.5 + PI / 8.0, TAU) - var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT)))) - if sector == _selected_sector: - return - _selected_sector = sector - _apply_selection_styles() - - -func _apply_selection_styles() -> void: - for sector: int in _buttons.size(): - var bubble: BubbleButton = _buttons[sector] - bubble.apply_profile() - if sector == _selected_sector: - bubble.add_theme_stylebox_override( - "normal", BubbleProfile.make_hover_style() - ) diff --git a/ui/quick_radial_menu.gd.uid b/ui/quick_radial_menu.gd.uid deleted file mode 100644 index ee4327f..0000000 --- a/ui/quick_radial_menu.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://5nr1c8x881sw diff --git a/ui/quick_radial_menu.tscn b/ui/quick_radial_menu.tscn deleted file mode 100644 index 66a0f45..0000000 --- a/ui/quick_radial_menu.tscn +++ /dev/null @@ -1,14 +0,0 @@ -[gd_scene load_steps=2 format=3] - -[ext_resource type="Script" path="res://ui/quick_radial_menu.gd" id="1_quick"] - -[node name="QuickRadialMenu" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -mouse_filter = 2 -z_index = 90 -script = ExtResource("1_quick") diff --git a/world/environment/netfishing_sky.gdshader b/world/environment/netfishing_sky.gdshader index bff5c56..b70ab79 100644 --- a/world/environment/netfishing_sky.gdshader +++ b/world/environment/netfishing_sky.gdshader @@ -4,7 +4,6 @@ uniform vec4 sky_top_color : source_color = vec4(0.204, 0.498, 0.643, 1.0); uniform vec4 sky_horizon_color : source_color = vec4(0.663, 0.843, 0.847, 1.0); uniform vec4 ground_bottom_color : source_color = vec4(0.157, 0.361, 0.439, 1.0); uniform vec4 ground_horizon_color : source_color = vec4(0.549, 0.749, 0.765, 1.0); -uniform float horizon_blend_width : hint_range(0.005, 0.15, 0.005) = 0.01; uniform vec3 sun_direction = vec3(0.0, 1.0, 0.0); uniform vec4 sun_color : source_color = vec4(1.0, 0.86, 0.46, 1.0); @@ -40,11 +39,7 @@ void sky() { vec3 base_color = mix( ground_color, sky_color, - smoothstep( - -horizon_blend_width, - horizon_blend_width, - view_direction.y - ) + smoothstep(-0.01, 0.01, view_direction.y) ); float alignment = dot(view_direction, normalize(sun_direction)); diff --git a/world/materials/stylized_water.gdshader b/world/materials/stylized_water.gdshader index 0bc45e1..76bc1a7 100644 --- a/world/materials/stylized_water.gdshader +++ b/world/materials/stylized_water.gdshader @@ -1,5 +1,5 @@ shader_type spatial; -render_mode blend_mix, depth_draw_never, cull_back, unshaded, fog_disabled; +render_mode blend_mix, depth_draw_never, cull_back, unshaded; uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; @@ -35,8 +35,6 @@ uniform float open_water_drift_strength : hint_range(0.0, 0.08, 0.001) = 0.045; uniform float distant_alpha_start : hint_range(10.0, 2000.0, 1.0) = 260.0; uniform float distant_alpha_end : hint_range(20.0, 5000.0, 1.0) = 1400.0; -uniform vec4 environment_tint : source_color = vec4(1.0); -uniform float environment_brightness : hint_range(0.1, 1.2, 0.01) = 1.0; varying vec3 world_position; varying float surface_view_depth; @@ -235,8 +233,6 @@ void fragment() { water_color = mix(water_color, deep_color.rgb, distant_mix * 0.72); water_alpha = mix(water_alpha, 0.96, distant_mix); - water_color *= environment_tint.rgb * environment_brightness; - ALBEDO = water_color; ALPHA = clamp(water_alpha, 0.1, 0.96); METALLIC = 0.0; diff --git a/world/materials/stylized_water.tres b/world/materials/stylized_water.tres index 100c598..40fc17d 100644 --- a/world/materials/stylized_water.tres +++ b/world/materials/stylized_water.tres @@ -32,5 +32,3 @@ shader_parameter/open_water_drift_speed = Vector2(0.01, -0.007) shader_parameter/open_water_drift_strength = 0.045 shader_parameter/distant_alpha_start = 260.0 shader_parameter/distant_alpha_end = 1400.0 -shader_parameter/environment_tint = Color(1, 1, 1, 1) -shader_parameter/environment_brightness = 1.0 diff --git a/world/materials/stylized_water_fresh.tres b/world/materials/stylized_water_fresh.tres index 6634e2a..66cc373 100644 --- a/world/materials/stylized_water_fresh.tres +++ b/world/materials/stylized_water_fresh.tres @@ -21,5 +21,3 @@ shader_parameter/open_water_drift_speed = Vector2(0.01, -0.007) shader_parameter/open_water_drift_strength = 0.045 shader_parameter/distant_alpha_start = 260.0 shader_parameter/distant_alpha_end = 1400.0 -shader_parameter/environment_tint = Color(1, 1, 1, 1) -shader_parameter/environment_brightness = 1.0 diff --git a/world/regions/starter_island_region.gd b/world/regions/starter_island_region.gd index c03243f..399c937 100644 --- a/world/regions/starter_island_region.gd +++ b/world/regions/starter_island_region.gd @@ -58,10 +58,6 @@ func get_pelican_landmark() -> Node3D: return get_node_or_null(pelican_landmark_path) as Node3D -func get_saltwater_shoreline_mesh() -> MeshInstance3D: - return get_node_or_null(^"ShorelineRibbons/Ocean") as MeshInstance3D - - func has_terrain_collision() -> bool: var collision_shape: CollisionShape3D = ( get_node_or_null(terrain_collision_shape_path) as CollisionShape3D diff --git a/world/shoreline_ambience.gd b/world/shoreline_ambience.gd deleted file mode 100644 index 959cb93..0000000 --- a/world/shoreline_ambience.gd +++ /dev/null @@ -1,156 +0,0 @@ -class_name ShorelineAmbience -extends Node - -@export_range(0.0, 20.0, 0.1) var near_distance: float = 2.0 -@export_range(1.0, 100.0, 0.5) var far_distance: float = 24.0 -@export_range(-40.0, 12.0, 0.5) var near_volume_db: float = 1.0 -@export_range(-80.0, 0.0, 0.5) var far_volume_db: float = -18.0 -@export_range(0.05, 1.0, 0.05) var distance_update_interval: float = 0.2 -@export_range(0.1, 20.0, 0.1) var volume_smoothing_speed: float = 4.0 - -@onready var _waves_audio: AudioStreamPlayer = %WavesAudio - -var _listener: Node3D -var _shoreline_segments: Array[PackedVector2Array] = [] -var _distance_update_remaining: float = 0.0 -var _target_volume_db: float = -80.0 -var _is_active := false - - -func _ready() -> void: - _configure_audio_loop(_waves_audio.stream) - _waves_audio.volume_db = -80.0 - set_process(false) - - -func configure(listener: Node3D, shoreline_mesh: MeshInstance3D) -> void: - _listener = listener - _shoreline_segments = _extract_shoreline_segments(shoreline_mesh) - _distance_update_remaining = 0.0 - if _shoreline_segments.is_empty(): - push_warning("Saltwater shoreline ambience has no coastline geometry.") - - -func set_active(active: bool) -> void: - _is_active = active - set_process(active) - if active: - _distance_update_remaining = 0.0 - _update_target_volume() - _waves_audio.volume_db = _target_volume_db - if not _waves_audio.playing and _waves_audio.stream != null: - _waves_audio.play() - else: - _waves_audio.stop() - _waves_audio.volume_db = -80.0 - - -func _process(delta: float) -> void: - if not _is_active: - return - _distance_update_remaining -= delta - if _distance_update_remaining <= 0.0: - _distance_update_remaining = distance_update_interval - _update_target_volume() - _waves_audio.volume_db = lerpf( - _waves_audio.volume_db, - _target_volume_db, - 1.0 - exp(-volume_smoothing_speed * delta), - ) - - -func _update_target_volume() -> void: - if _listener == null or _shoreline_segments.is_empty(): - _target_volume_db = -80.0 - return - var listener_position := Vector2( - _listener.global_position.x, - _listener.global_position.z, - ) - var distance := distance_to_segments(listener_position, _shoreline_segments) - var blend := clampf( - inverse_lerp(near_distance, maxf(near_distance + 0.01, far_distance), distance), - 0.0, - 1.0, - ) - _target_volume_db = lerpf(near_volume_db, far_volume_db, smoothstep(0.0, 1.0, blend)) - - -func _extract_shoreline_segments( - shoreline_mesh: MeshInstance3D, -) -> Array[PackedVector2Array]: - var segments: Array[PackedVector2Array] = [] - var seen_segments: Dictionary = {} - if shoreline_mesh == null or shoreline_mesh.mesh == null: - return segments - for surface_index in shoreline_mesh.mesh.get_surface_count(): - var arrays := shoreline_mesh.mesh.surface_get_arrays(surface_index) - var vertices: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX] - var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX] - if indices.is_empty(): - continue - for index_offset in range(0, indices.size() - 2, 3): - var triangle := PackedVector2Array() - for corner in 3: - var vertex := shoreline_mesh.to_global( - vertices[indices[index_offset + corner]] - ) - triangle.append(Vector2(vertex.x, vertex.z)) - _append_unique_segment(segments, seen_segments, triangle[0], triangle[1]) - _append_unique_segment(segments, seen_segments, triangle[1], triangle[2]) - _append_unique_segment(segments, seen_segments, triangle[2], triangle[0]) - return segments - - -func _append_unique_segment( - segments: Array[PackedVector2Array], - seen_segments: Dictionary, - start: Vector2, - end: Vector2, -) -> void: - if start.distance_squared_to(end) <= 0.000001: - return - # The baked ribbon repeats shared triangle edges. Quantized canonical keys - # keep only distinct segments without an O(n²) startup pass. - var first := start - var second := end - if first.x > second.x or (is_equal_approx(first.x, second.x) and first.y > second.y): - first = end - second = start - var key := "%d,%d:%d,%d" % [ - roundi(first.x * 10000.0), - roundi(first.y * 10000.0), - roundi(second.x * 10000.0), - roundi(second.y * 10000.0), - ] - if seen_segments.has(key): - return - seen_segments[key] = true - segments.append(PackedVector2Array([start, end])) - - -static func distance_to_segments( - point: Vector2, - segments: Array[PackedVector2Array], -) -> float: - var closest_squared := INF - for segment in segments: - if segment.size() < 2: - continue - var closest := Geometry2D.get_closest_point_to_segment( - point, - segment[0], - segment[1], - ) - closest_squared = minf(closest_squared, point.distance_squared_to(closest)) - return sqrt(closest_squared) if closest_squared < INF else INF - - -func _configure_audio_loop(stream: AudioStream) -> void: - var wav := stream as AudioStreamWAV - if wav == null: - return - wav.loop_mode = AudioStreamWAV.LOOP_FORWARD - if wav.loop_end <= wav.loop_begin: - wav.loop_begin = 0 - wav.loop_end = int(round(wav.get_length() * wav.mix_rate)) diff --git a/world/shoreline_ambience.gd.uid b/world/shoreline_ambience.gd.uid deleted file mode 100644 index 3188ec7..0000000 --- a/world/shoreline_ambience.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0c3o2vy76fg3 diff --git a/world/test_world.gd b/world/test_world.gd index 5d6660a..189c119 100644 --- a/world/test_world.gd +++ b/world/test_world.gd @@ -61,10 +61,6 @@ func get_pelican_convenience_landmark() -> Node3D: return _starter_island.get_pelican_landmark() -func get_saltwater_shoreline_mesh() -> MeshInstance3D: - return _starter_island.get_saltwater_shoreline_mesh() - - func _get_regions() -> Array[WorldRegion]: var regions: Array[WorldRegion] = [] for child: Node in _regions_root.get_children(): diff --git a/world/world_time_visual_controller.gd b/world/world_time_visual_controller.gd index c6a9ed4..b7b1839 100644 --- a/world/world_time_visual_controller.gd +++ b/world/world_time_visual_controller.gd @@ -9,12 +9,6 @@ const RAIN_PARTICLE_AMOUNT: int = 560 const RAIN_VELOCITY_MIN: float = 16.0 const RAIN_VELOCITY_MAX: float = 20.0 const RAIN_DROP_SIZE := Vector3(0.014, 0.34, 0.014) -const SALT_WATER_MATERIAL: ShaderMaterial = preload( - "res://world/materials/stylized_water.tres" -) -const FRESH_WATER_MATERIAL: ShaderMaterial = preload( - "res://world/materials/stylized_water_fresh.tres" -) const DAY_SKY_TOP := Color(0.204, 0.498, 0.643) const DAY_SKY_HORIZON := Color(0.663, 0.843, 0.847) @@ -32,7 +26,6 @@ const NIGHT_GROUND_HORIZON := Color(0.075, 0.135, 0.22) const NIGHT_AMBIENT := Color(0.28, 0.35, 0.48) const NIGHT_FOG := Color(0.13, 0.21, 0.32) const NIGHT_SUN := Color(0.35, 0.44, 0.62) -const NIGHT_WATER_TINT := Color(0.34, 0.48, 0.58) const WARM_SKY_TOP := Color(0.31, 0.30, 0.42) const WARM_SKY_HORIZON := Color(0.96, 0.48, 0.22) @@ -41,10 +34,13 @@ const WARM_GROUND_HORIZON := Color(0.82, 0.34, 0.18) const WARM_AMBIENT := Color(0.92, 0.58, 0.40) const WARM_FOG := Color(0.74, 0.39, 0.27) const WARM_SUN := Color(1.0, 0.58, 0.30) -const WARM_WATER_TINT := Color(0.78, 0.62, 0.58) const WARM_SUN_DISC := Color(1.0, 0.45, 0.16) const MOON_DISC := Color(0.78, 0.88, 1.0) +const CLOUDY_TINT := Color(0.53, 0.61, 0.66) +const RAINY_TINT := Color(0.31, 0.42, 0.50) +const FOGGY_TINT := Color(0.62, 0.70, 0.72) + var _time_service: WorldTimeService var _weather_service: WorldWeatherService var _world_environment: WorldEnvironment @@ -220,31 +216,38 @@ func _apply_time(time_hours: float) -> void: var fog_color: Color = _blended_color( NIGHT_FOG, DAY_FOG, WARM_FOG, daylight, warmth ) - _sky_material.set_shader_parameter( - "sky_top_color", sky_top + var weather_tint: Color = _weather_color() + var tint_strength: float = _weather_value( + 0.0, 0.30, 0.48, 0.62 ) _sky_material.set_shader_parameter( - "sky_horizon_color", - sky_horizon, + "sky_top_color", sky_top.lerp(weather_tint, tint_strength) + ) + _sky_material.set_shader_parameter( + "sky_horizon_color", sky_horizon.lerp(weather_tint, tint_strength) ) _sky_material.set_shader_parameter( "ground_bottom_color", - ground_bottom, + ground_bottom.lerp(weather_tint, tint_strength * 0.62), ) _sky_material.set_shader_parameter( "ground_horizon_color", - ground_horizon, + ground_horizon.lerp(weather_tint, tint_strength * 0.76), ) _environment.background_energy_multiplier = ( lerpf(0.52, 0.85, daylight) - * _weather_value(1.0, 0.82, 0.66, 1.0) + * _weather_value(1.0, 0.82, 0.66, 0.74) + ) + _environment.ambient_light_color = ambient.lerp( + weather_tint, tint_strength * 0.45 ) - _environment.ambient_light_color = ambient _environment.ambient_light_energy = ( lerpf(0.66, 1.08, daylight) * _weather_value(1.0, 0.88, 0.76, 0.82) ) - _environment.fog_light_color = fog_color + _environment.fog_light_color = fog_color.lerp( + weather_tint, tint_strength * 0.82 + ) _environment.fog_light_energy = ( lerpf(0.56, 0.82, daylight) * _weather_value(1.0, 0.92, 0.82, 1.05) @@ -252,24 +255,25 @@ func _apply_time(time_hours: float) -> void: _environment.fog_aerial_perspective = _weather_value( 0.35, 0.48, 0.62, 0.92 ) - _environment.fog_sky_affect = 0.0 + _environment.fog_sky_affect = _weather_value( + 0.35, 0.48, 0.68, 0.94 + ) _environment.fog_depth_curve = _weather_value( 1.6, 1.5, 1.4, 1.18 ) _environment.fog_depth_begin = _weather_value( - 42.0, 32.0, 20.0, 3.0 + 42.0, 32.0, 20.0, 4.0 ) _environment.fog_depth_end = _weather_value( - 170.0, 140.0, 95.0, 28.0 + 170.0, 140.0, 95.0, 42.0 ) - _apply_water_environment(daylight, warmth) _environment.adjustment_brightness = ( lerpf(0.93, 0.98, daylight) - * _weather_value(1.0, 0.97, 0.92, 1.0) + * _weather_value(1.0, 0.97, 0.92, 0.96) ) _environment.adjustment_saturation = ( lerpf(0.82, 0.91, daylight) - * _weather_value(1.0, 0.88, 0.78, 1.0) + * _weather_value(1.0, 0.88, 0.78, 0.70) ) _sun.rotation_degrees = Vector3( -360.0 * fposmod(hour - WorldTimeService.DAY_START_HOUR, 24.0) / 24.0, @@ -284,7 +288,7 @@ func _apply_time(time_hours: float) -> void: ) _sky_material.set_shader_parameter( "sun_visibility", - daylight * _weather_value(1.0, 0.65, 0.28, 1.0), + daylight * _weather_value(1.0, 0.65, 0.28, 0.15), ) _sky_material.set_shader_parameter( "moon_direction", -_sun.global_transform.basis.z.normalized() @@ -292,7 +296,7 @@ func _apply_time(time_hours: float) -> void: _sky_material.set_shader_parameter("moon_color", MOON_DISC) _sky_material.set_shader_parameter( "moon_visibility", - (1.0 - daylight) * _weather_value(1.0, 0.72, 0.36, 1.0), + (1.0 - daylight) * _weather_value(1.0, 0.72, 0.36, 0.20), ) _sun.light_color = _blended_color( NIGHT_SUN, DAY_SUN, WARM_SUN, daylight, warmth @@ -304,32 +308,6 @@ func _apply_time(time_hours: float) -> void: _update_rain_amount() -func _apply_water_environment( - daylight: float, - warmth: float, -) -> void: - var water_tint := _blended_color( - NIGHT_WATER_TINT, - Color.WHITE, - WARM_WATER_TINT, - daylight, - warmth, - ) - var water_brightness := ( - lerpf(0.34, 1.0, daylight) - * _weather_value(1.0, 0.90, 0.78, 1.0) - ) - for material: ShaderMaterial in [ - SALT_WATER_MATERIAL, - FRESH_WATER_MATERIAL, - ]: - material.set_shader_parameter("environment_tint", water_tint) - material.set_shader_parameter( - "environment_brightness", - water_brightness, - ) - - func _on_weather_changed( weather: WorldWeatherService.Weather, _seconds_remaining: float, @@ -371,6 +349,25 @@ func _weather_state_value( return sunny +func _weather_color() -> Color: + return _weather_state_color(_weather_from).lerp( + _weather_state_color(_weather_to), _weather_transition + ) + + +func _weather_state_color( + weather: WorldWeatherService.Weather, +) -> Color: + match weather: + WorldWeatherService.Weather.CLOUDY: + return CLOUDY_TINT + WorldWeatherService.Weather.RAINY: + return RAINY_TINT + WorldWeatherService.Weather.FOGGY: + return FOGGY_TINT + return Color.WHITE + + func _update_rain_amount() -> void: if _rain == null: return