diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..219c096336b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +# .dockerignore +node_modules +*.log +*.md +.gitignore +Dockerfile +.env \ No newline at end of file diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index f2e17898334..fea857355a0 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -55,15 +55,15 @@ jobs: - name: Create release branch run: git checkout -b release - # In order to be able to open a PR into beta, we need the branch to have at least one change. - - name: Overwrite RELEASE file + # In order to be able to open a PR into beta, we need the branch to have at least one commit. + # The first commit is _usually_ just bumping the version number, so we can kill 2 birds with 1 stone here + - name: Bump release version run: | git config --local user.name "github-actions[bot]" git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - echo "Release v${{ github.event.inputs.versionName }}" > RELEASE - git add RELEASE - git commit -m "Stage release v${{ github.event.inputs.versionName }}" - + pnpm --no-git-tag-version version ${{ github.events.inputs.versionName }} + git commit -am "Stage release for v${{ github.events.inputs.versionName }}" + - name: Push new branch run: git push origin release diff --git a/.github/workflows/deploy-beta.yml b/.github/workflows/deploy-beta.yml index 341999dcd45..5abba4488be 100644 --- a/.github/workflows/deploy-beta.yml +++ b/.github/workflows/deploy-beta.yml @@ -22,8 +22,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - uses: actions/setup-node@v4 with: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 528906196e5..1f2c1259dd1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,8 +20,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - uses: actions/setup-node@v4 with: diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 6e056bc4032..d8482cba83c 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -27,20 +27,18 @@ jobs: # Only push docs when running on pushes to main/beta DRY_RUN: ${{github.event_name != 'push' || (github.ref_name != 'beta' && github.ref_name != 'main')}} - strategy: - fail-fast: false - steps: - name: Checkout repository for Typedoc uses: actions/checkout@v4 with: - submodules: 'recursive' path: pokerogue_docs - - - name: Install OS package - run: | - sudo apt update - sudo apt install -y git openssh-client + sparse-checkout: | + /* + !/public/ + /public/images/pokemon/variant/_exp_masterlist.json + /public/images/pokemon/variant/_masterlist.json + /public/images/logo.png + sparse-checkout-cone-mode: false - name: Install pnpm uses: pnpm/action-setup@v4 diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index edecae64f95..e1314c2cbd3 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -30,8 +30,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - name: Set up Node uses: actions/setup-node@v4 diff --git a/.github/workflows/test-shard-template.yml b/.github/workflows/test-shard-template.yml index 79aea56bbd0..6f4728863b4 100644 --- a/.github/workflows/test-shard-template.yml +++ b/.github/workflows/test-shard-template.yml @@ -32,8 +32,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 39506096298..e1d6e3af60e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,6 +28,10 @@ jobs: steps: - name: checkout uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/test-filters.yml + sparse-checkout-cone-mode: false - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 id: filter diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04ab7ff4faa..c24b648c490 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,7 +80,8 @@ Notable topics include: - [Commenting your code](./docs/comments.md) - [Linting & Formatting](./docs/linting.md) - [Localization](./docs/localization.md) -- [Enemy AI move selection](./docs/enemy-ai.md) +- [Enemy AI move selection](./docs/enemy-ai.md) +- [Running with Podman](./docs/podman.md) Again, if you have unanswered questions please feel free to ask! diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..ddb865b4831 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# syntax=docker/dockerfile:1 +ARG NODE_VERSION=22.14 +ARG OS=alpine + +FROM node:${NODE_VERSION}-${OS} + +# Create non-root user +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# Install git (for potential runtime needs) +RUN apk add --no-cache git + +# Set working directory +WORKDIR /app + +# Enable and prepare pnpm +RUN corepack enable && corepack prepare pnpm@10.14.0 --activate + +COPY . . + +# Copy package files +COPY package.json pnpm-lock.yaml ./ + +# Install all dependencies +RUN --mount=type=cache,target=/home/appuser/.pnpm-store \ + pnpm install --frozen-lockfile && \ + rm -rf /home/appuser/.pnpm-store/* + +# Change ownership +RUN chown -R appuser:appgroup /app + +# Switch to non-root user +USER appuser + +# Set environment variables +ENV VITE_BYPASS_LOGIN=1 \ + VITE_BYPASS_TUTORIAL=0 \ + NEXT_TELEMETRY_DISABLED=1 \ + PNP_HOME=/home/appuser/.shrc \ + NODE_ENV=development \ + PORT=8000 + +# Expose port +EXPOSE $PORT + +# Start the app in development mode +CMD ["pnpm", "run", "start:podman"] diff --git a/RELEASE b/RELEASE deleted file mode 100644 index a1a9f30b0e8..00000000000 --- a/RELEASE +++ /dev/null @@ -1 +0,0 @@ -Release v1.10.0 diff --git a/docs/podman.md b/docs/podman.md new file mode 100644 index 00000000000..dea52131e92 --- /dev/null +++ b/docs/podman.md @@ -0,0 +1,27 @@ +# Using Podman + +## Requirements + +* `podman >=5.x` + +## Steps + +1. `podman build -t pokerogue -f Dockerfile .` +2. `podman create --name temp-pokerogue localhost/pokerogue` +3. `podman cp temp-pokerogue:/app/node_modules ./` +4. `podman cp temp-pokerogue:/app/public/locales ./public/` +5. `podman rm temp-pokerogue` +6. `podman run --rm -p 8000:8000 -v $(pwd):/app:Z --userns=keep-id -u $(id -u):$(id -g) localhost/pokerogue` +7. Visit `http://localhost:8000/` + +Note: + +1. Steps 2,3,4 are required because mounting working directory without installed `node_modules/` and assets locally will be empty, +this way we prevent it by copying them from the container itself to local directory + +2. `podman run` may take a couple of minutes to mount the working directory + +### Running tests inside container + +`podman run --rm -p 8000:8000 -v $(pwd):/app:Z --userns=keep-id -u $(id -u):$(id -g) localhost/pokerogue pnpm test:silent +` \ No newline at end of file diff --git a/package.json b/package.json index 65936f2599a..ee5b001a589 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "start:prod": "vite --mode production", "start:beta": "vite --mode beta", "start:dev": "vite --mode development", + "start:podman": "vite --mode development --host 0.0.0.0 --port $PORT", "build": "vite build", "build:beta": "vite build --mode beta", "preview": "vite preview", @@ -46,7 +47,7 @@ "lefthook": "^1.12.2", "msw": "^2.10.4", "phaser3spectorjs": "^0.0.8", - "typedoc": "^0.28.8", + "typedoc": "0.28.7", "typedoc-github-theme": "^0.3.1", "typedoc-plugin-coverage": "^4.0.1", "typedoc-plugin-mdn-links": "^5.0.9", @@ -71,5 +72,6 @@ }, "engines": { "node": ">=22.0.0" - } + }, + "packageManager": "pnpm@10.14.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54012c3dd86..e750095a4c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,7 +59,7 @@ importers: version: 22.16.5 '@vitest/coverage-istanbul': specifier: ^3.2.4 - version: 3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)) + version: 3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)) '@vitest/expect': specifier: ^3.2.4 version: 3.2.4 @@ -88,32 +88,32 @@ importers: specifier: ^0.0.8 version: 0.0.8 typedoc: - specifier: ^0.28.8 - version: 0.28.8(typescript@5.8.3) + specifier: 0.28.7 + version: 0.28.7(typescript@5.8.3) typedoc-github-theme: specifier: ^0.3.1 - version: 0.3.1(typedoc@0.28.8(typescript@5.8.3)) + version: 0.3.1(typedoc@0.28.7(typescript@5.8.3)) typedoc-plugin-coverage: specifier: ^4.0.1 - version: 4.0.1(typedoc@0.28.8(typescript@5.8.3)) + version: 4.0.1(typedoc@0.28.7(typescript@5.8.3)) typedoc-plugin-mdn-links: specifier: ^5.0.9 - version: 5.0.9(typedoc@0.28.8(typescript@5.8.3)) + version: 5.0.9(typedoc@0.28.7(typescript@5.8.3)) typescript: specifier: ^5.8.3 version: 5.8.3 vite: specifier: ^7.0.6 - version: 7.0.6(@types/node@22.16.5)(yaml@2.8.0) + version: 7.0.6(@types/node@22.16.5)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0)) + version: 5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1)) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0) + version: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1) vitest-canvas-mock: specifier: ^0.3.3 - version: 0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)) + version: 0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)) packages: @@ -441,8 +441,8 @@ packages: cpu: [x64] os: [win32] - '@gerrit0/mini-shiki@3.8.1': - resolution: {integrity: sha512-HVZW+8pxoOExr5ZMPK15U79jQAZTO/S6i5byQyyZGjtNj+qaYd82cizTncwFzTQgiLo8uUBym6vh+/1tfJklTw==} + '@gerrit0/mini-shiki@3.12.2': + resolution: {integrity: sha512-HKZPmO8OSSAAo20H2B3xgJdxZaLTwtlMwxg0967scnrDlPwe6j5+ULGHyIqwgTbFCn9yv/ff8CmfWZLE9YKBzA==} '@inquirer/checkbox@4.2.0': resolution: {integrity: sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==} @@ -712,17 +712,17 @@ packages: cpu: [x64] os: [win32] - '@shikijs/engine-oniguruma@3.8.1': - resolution: {integrity: sha512-KGQJZHlNY7c656qPFEQpIoqOuC4LrxjyNndRdzk5WKB/Ie87+NJCF1xo9KkOUxwxylk7rT6nhlZyTGTC4fCe1g==} + '@shikijs/engine-oniguruma@3.12.2': + resolution: {integrity: sha512-hozwnFHsLvujK4/CPVHNo3Bcg2EsnG8krI/ZQ2FlBlCRpPZW4XAEQmEwqegJsypsTAN9ehu2tEYe30lYKSZW/w==} - '@shikijs/langs@3.8.1': - resolution: {integrity: sha512-TjOFg2Wp1w07oKnXjs0AUMb4kJvujML+fJ1C5cmEj45lhjbUXtziT1x2bPQb9Db6kmPhkG5NI2tgYW1/DzhUuQ==} + '@shikijs/langs@3.12.2': + resolution: {integrity: sha512-bVx5PfuZHDSHoBal+KzJZGheFuyH4qwwcwG/n+MsWno5cTlKmaNtTsGzJpHYQ8YPbB5BdEdKU1rga5/6JGY8ww==} - '@shikijs/themes@3.8.1': - resolution: {integrity: sha512-Vu3t3BBLifc0GB0UPg2Pox1naTemrrvyZv2lkiSw3QayVV60me1ujFQwPZGgUTmwXl1yhCPW8Lieesm0CYruLQ==} + '@shikijs/themes@3.12.2': + resolution: {integrity: sha512-fTR3QAgnwYpfGczpIbzPjlRnxyONJOerguQv1iwpyQZ9QXX4qy/XFQqXlf17XTsorxnHoJGbH/LXBvwtqDsF5A==} - '@shikijs/types@3.8.1': - resolution: {integrity: sha512-5C39Q8/8r1I26suLh+5TPk1DTrbY/kn3IdWA5HdizR0FhlhD05zx5nKCqhzSfDHH3p4S0ZefxWd77DLV+8FhGg==} + '@shikijs/types@3.12.2': + resolution: {integrity: sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -1818,8 +1818,8 @@ packages: peerDependencies: typedoc: 0.27.x || 0.28.x - typedoc@0.28.8: - resolution: {integrity: sha512-16GfLopc8icHfdvqZDqdGBoS2AieIRP2rpf9mU+MgN+gGLyEQvAO0QgOa6NJ5QNmQi0LFrDY9in4F2fUNKgJKA==} + typedoc@0.28.7: + resolution: {integrity: sha512-lpz0Oxl6aidFkmS90VQDQjk/Qf2iw0IUvFqirdONBdj7jPSN9mGXhy66BcGNDxx5ZMyKKiBVAREvPEzT6Uxipw==} engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: @@ -2020,8 +2020,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.0: - resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} hasBin: true @@ -2300,12 +2300,12 @@ snapshots: '@esbuild/win32-x64@0.25.8': optional: true - '@gerrit0/mini-shiki@3.8.1': + '@gerrit0/mini-shiki@3.12.2': dependencies: - '@shikijs/engine-oniguruma': 3.8.1 - '@shikijs/langs': 3.8.1 - '@shikijs/themes': 3.8.1 - '@shikijs/types': 3.8.1 + '@shikijs/engine-oniguruma': 3.12.2 + '@shikijs/langs': 3.12.2 + '@shikijs/themes': 3.12.2 + '@shikijs/types': 3.12.2 '@shikijs/vscode-textmate': 10.0.2 '@inquirer/checkbox@4.2.0(@types/node@22.16.5)': @@ -2534,20 +2534,20 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.46.1': optional: true - '@shikijs/engine-oniguruma@3.8.1': + '@shikijs/engine-oniguruma@3.12.2': dependencies: - '@shikijs/types': 3.8.1 + '@shikijs/types': 3.12.2 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.8.1': + '@shikijs/langs@3.12.2': dependencies: - '@shikijs/types': 3.8.1 + '@shikijs/types': 3.12.2 - '@shikijs/themes@3.8.1': + '@shikijs/themes@3.12.2': dependencies: - '@shikijs/types': 3.8.1 + '@shikijs/types': 3.12.2 - '@shikijs/types@3.8.1': + '@shikijs/types@3.12.2': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -2586,7 +2586,7 @@ snapshots: '@types/unist@3.0.3': {} - '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0))': + '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1))': dependencies: '@istanbuljs/schema': 0.1.3 debug: 4.4.1 @@ -2598,7 +2598,7 @@ snapshots: magicast: 0.3.5 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0) + vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -2610,14 +2610,14 @@ snapshots: chai: 5.2.1 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0))': + '@vitest/mocker@3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: msw: 2.10.4(@types/node@22.16.5)(typescript@5.8.3) - vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0) + vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -3663,26 +3663,26 @@ snapshots: type-fest@4.41.0: {} - typedoc-github-theme@0.3.1(typedoc@0.28.8(typescript@5.8.3)): + typedoc-github-theme@0.3.1(typedoc@0.28.7(typescript@5.8.3)): dependencies: - typedoc: 0.28.8(typescript@5.8.3) + typedoc: 0.28.7(typescript@5.8.3) - typedoc-plugin-coverage@4.0.1(typedoc@0.28.8(typescript@5.8.3)): + typedoc-plugin-coverage@4.0.1(typedoc@0.28.7(typescript@5.8.3)): dependencies: - typedoc: 0.28.8(typescript@5.8.3) + typedoc: 0.28.7(typescript@5.8.3) - typedoc-plugin-mdn-links@5.0.9(typedoc@0.28.8(typescript@5.8.3)): + typedoc-plugin-mdn-links@5.0.9(typedoc@0.28.7(typescript@5.8.3)): dependencies: - typedoc: 0.28.8(typescript@5.8.3) + typedoc: 0.28.7(typescript@5.8.3) - typedoc@0.28.8(typescript@5.8.3): + typedoc@0.28.7(typescript@5.8.3): dependencies: - '@gerrit0/mini-shiki': 3.8.1 + '@gerrit0/mini-shiki': 3.12.2 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 typescript: 5.8.3 - yaml: 2.8.0 + yaml: 2.8.1 typescript@5.8.3: {} @@ -3705,13 +3705,13 @@ snapshots: util-deprecate@1.0.2: {} - vite-node@3.2.4(@types/node@22.16.5)(yaml@2.8.0): + vite-node@3.2.4(@types/node@22.16.5)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0) + vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -3726,18 +3726,18 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1)): dependencies: debug: 4.4.1 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.8.3) optionalDependencies: - vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0) + vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0): + vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1): dependencies: esbuild: 0.25.8 fdir: 6.4.6(picomatch@4.0.3) @@ -3748,18 +3748,18 @@ snapshots: optionalDependencies: '@types/node': 22.16.5 fsevents: 2.3.3 - yaml: 2.8.0 + yaml: 2.8.1 - vitest-canvas-mock@0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0)): + vitest-canvas-mock@0.3.3(vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1)): dependencies: jest-canvas-mock: 2.5.2 - vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0) + vitest: 3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1) - vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.0): + vitest@3.2.4(@types/node@22.16.5)(jsdom@26.1.0)(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.0)) + '@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@22.16.5)(typescript@5.8.3))(vite@7.0.6(@types/node@22.16.5)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -3777,8 +3777,8 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.0) - vite-node: 3.2.4(@types/node@22.16.5)(yaml@2.8.0) + vite: 7.0.6(@types/node@22.16.5)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.16.5)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.16.5 @@ -3862,7 +3862,7 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.0: {} + yaml@2.8.1: {} yargs-parser@21.1.1: {} diff --git a/public/images/ui/language_icon.png b/public/images/ui/language_icon.png new file mode 100644 index 00000000000..ebe0671ca51 Binary files /dev/null and b/public/images/ui/language_icon.png differ diff --git a/public/images/ui/legacy/language_icon.png b/public/images/ui/legacy/language_icon.png new file mode 100644 index 00000000000..ebe0671ca51 Binary files /dev/null and b/public/images/ui/legacy/language_icon.png differ diff --git a/public/locales b/public/locales index 090bfefaf7e..74de730a642 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit 090bfefaf7e9d4efcbca61fa78a9cdf5d701830b +Subproject commit 74de730a64272c8e9ca0a4cdcf3426cbf1b0aeda diff --git a/scripts/create-test/boilerplates/default.ts b/scripts/create-test/boilerplates/default.ts index fa914b150c2..e644e740594 100644 --- a/scripts/create-test/boilerplates/default.ts +++ b/scripts/create-test/boilerplates/default.ts @@ -1,7 +1,10 @@ import { AbilityId } from "#enums/ability-id"; +import { BattlerIndex } from "#enums/battler-index"; import { MoveId } from "#enums/move-id"; +import { MoveResult } from "#enums/move-result"; import { SpeciesId } from "#enums/species-id"; import { GameManager } from "#test/test-utils/game-manager"; +import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -32,12 +35,18 @@ describe("{{description}}", () => { .enemyLevel(100); }); + // Find more awesome utility functions inside `#test/test-utils`! it("should do XYZ", async () => { await game.classicMode.startBattle([SpeciesId.FEEBAS]); + const feebas = game.field.getPlayerPokemon(); + game.move.use(MoveId.SPLASH); + await game.move.forceEnemyMove(MoveId.CELEBRATE); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toEndOfTurn(); - expect(true).toBe(true); + expect(feebas).toHaveUsedMove({ move: MoveId.SPLASH, result: MoveResult.SUCCESS }); + expect(game.textInterceptor.logs).toContain(i18next.t("moveTriggers:splash")); }); }); diff --git a/src/@types/api/pokerogue-daily-api.ts b/src/@types/api/pokerogue-daily-api.ts index 862ff2f51a3..838af2a2a34 100644 --- a/src/@types/api/pokerogue-daily-api.ts +++ b/src/@types/api/pokerogue-daily-api.ts @@ -1,4 +1,4 @@ -import type { ScoreboardCategory } from "#ui/containers/daily-run-scoreboard"; +import type { ScoreboardCategory } from "#ui/daily-run-scoreboard"; export interface GetDailyRankingsRequest { category: ScoreboardCategory; diff --git a/src/@types/api/pokerogue-save-data-api.ts b/src/@types/api/pokerogue-save-data-api.ts index ebc80ac4ce0..c33d775f114 100644 --- a/src/@types/api/pokerogue-save-data-api.ts +++ b/src/@types/api/pokerogue-save-data-api.ts @@ -1,4 +1,4 @@ -import type { SessionSaveData, SystemSaveData } from "#system/game-data"; +import type { SessionSaveData, SystemSaveData } from "#types/save-data"; export interface UpdateAllSavedataRequest { system: SystemSaveData; diff --git a/src/@types/api/pokerogue-system-save-data-api.ts b/src/@types/api/pokerogue-system-save-data-api.ts index 133f9cda506..2e79b4fb92c 100644 --- a/src/@types/api/pokerogue-system-save-data-api.ts +++ b/src/@types/api/pokerogue-system-save-data-api.ts @@ -1,4 +1,4 @@ -import type { SystemSaveData } from "#system/game-data"; +import type { SystemSaveData } from "#types/save-data"; export interface GetSystemSavedataRequest { clientSessionId: string; diff --git a/src/@types/arena-tags.ts b/src/@types/arena-tags.ts index 390d95a7daa..73f26af052a 100644 --- a/src/@types/arena-tags.ts +++ b/src/@types/arena-tags.ts @@ -1,7 +1,7 @@ import type { ArenaTagTypeMap } from "#data/arena-tag"; import type { ArenaTagType } from "#enums/arena-tag-type"; // biome-ignore lint/correctness/noUnusedImports: TSDocs -import type { SessionSaveData } from "#system/game-data"; +import type { SessionSaveData } from "#types/save-data"; import type { ObjectValues } from "#types/type-helpers"; /** Subset of {@linkcode ArenaTagType}s that apply some negative effect to pokemon that switch in ({@link https://bulbapedia.bulbagarden.net/wiki/List_of_moves_that_cause_entry_hazards#List_of_traps | entry hazards} and Imprison. */ @@ -38,6 +38,7 @@ type SerializableArenaTagTypeMap = Pick; + +export interface RunEntry { + entry: SessionSaveData; + isVictory: boolean; + /*Automatically set to false at the moment - implementation TBD*/ + isFavorite: boolean; +} + +export interface StarterDataEntry { + moveset: StarterMoveset | StarterFormMoveData | null; + eggMoves: number; + candyCount: number; + friendship: number; + abilityAttr: number; + passiveAttr: number; + valueReduction: number; + classicWinCount: number; +} + +export interface StarterData { + [key: number]: StarterDataEntry; +} + +// TODO: Rework into a bitmask +export type TutorialFlags = { + [key in Tutorial]: boolean; +}; + +// TODO: Rework into a bitmask +export interface SeenDialogues { + [key: string]: boolean; +} diff --git a/src/@types/session-save-migrator.ts b/src/@types/session-save-migrator.ts index 56518eaa8b7..c8f53236c63 100644 --- a/src/@types/session-save-migrator.ts +++ b/src/@types/session-save-migrator.ts @@ -1,4 +1,4 @@ -import type { SessionSaveData } from "#system/game-data"; +import type { SessionSaveData } from "./save-data"; export interface SessionSaveMigrator { version: string; diff --git a/src/@types/system-save-migrator.ts b/src/@types/system-save-migrator.ts index 80fff9c7848..4cbcc4c3e15 100644 --- a/src/@types/system-save-migrator.ts +++ b/src/@types/system-save-migrator.ts @@ -1,4 +1,4 @@ -import type { SystemSaveData } from "#system/game-data"; +import type { SystemSaveData } from "./save-data"; export interface SystemSaveMigrator { version: string; diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d7681f5ff85..a8e8aa85121 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -121,13 +121,13 @@ import { vouchers } from "#system/voucher"; import { trainerConfigs } from "#trainers/trainer-config"; import type { HeldModifierConfig } from "#types/held-modifier-config"; import type { Localizable } from "#types/locales"; -import { AbilityBar } from "#ui/containers/ability-bar"; -import { ArenaFlyout } from "#ui/containers/arena-flyout"; -import { CandyBar } from "#ui/containers/candy-bar"; -import { CharSprite } from "#ui/containers/char-sprite"; -import { PartyExpBar } from "#ui/containers/party-exp-bar"; -import { PokeballTray } from "#ui/containers/pokeball-tray"; -import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container"; +import { AbilityBar } from "#ui/ability-bar"; +import { ArenaFlyout } from "#ui/arena-flyout"; +import { CandyBar } from "#ui/candy-bar"; +import { CharSprite } from "#ui/char-sprite"; +import { PartyExpBar } from "#ui/party-exp-bar"; +import { PokeballTray } from "#ui/pokeball-tray"; +import { PokemonInfoContainer } from "#ui/pokemon-info-container"; import { addTextObject, getTextColor } from "#ui/text"; import { UI } from "#ui/ui"; import { addUiThemeOverrides } from "#ui/ui-theme"; @@ -3108,7 +3108,7 @@ export class BattleScene extends SceneBase { * Apply all modifiers that match `modifierType` in a random order * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` - * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @param args The list of arguments needed to invoke `modifierType.apply` * @returns the list of all modifiers that matched `modifierType` and were applied. */ applyShuffledModifiers( @@ -3140,7 +3140,7 @@ export class BattleScene extends SceneBase { * Apply all modifiers that match `modifierType` * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` - * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @param args The list of arguments needed to invoke `modifierType.apply` * @returns the list of all modifiers that matched `modifierType` and were applied. */ applyModifiers( @@ -3175,7 +3175,7 @@ export class BattleScene extends SceneBase { * Apply the first modifier that matches `modifierType` * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` - * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @param args The list of arguments needed to invoke `modifierType.apply` * @returns the first modifier that matches `modifierType` and was applied; return `null` if none matched */ applyModifier( @@ -3323,7 +3323,7 @@ export class BattleScene extends SceneBase { /** * This function retrieves the sprite and audio keys for active Pokemon. * Active Pokemon include both enemy and player Pokemon of the current wave. - * Note: Questions on garbage collection go to @frutescens + * Note: Questions on garbage collection go to `@frutescens` * @returns a string array of active sprite and audio keys that should not be deleted */ getActiveKeys(): string[] { diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 62f9d6a0d98..9c37ed708c6 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -510,7 +510,7 @@ export class ClearWeatherAbAttr extends AbAttr { private weather: WeatherType[]; /** - * @param weather {@linkcode WeatherType[]} - the weather to be removed + * @param weather - The weather to be removed */ constructor(weather: WeatherType[]) { super(true); @@ -540,7 +540,7 @@ export class ClearTerrainAbAttr extends AbAttr { private terrain: TerrainType[]; /** - * @param terrain {@linkcode TerrainType[]} - the terrain to be removed + * @param terrain - the terrain to be removed */ constructor(terrain: TerrainType[]) { super(true); @@ -658,7 +658,6 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr { /** * Reduces the damage dealt to an allied Pokemon. Used by Friend Guard. - * @see {@linkcode applyPreDefend} */ export class AlliedFieldDamageReductionAbAttr extends PreDefendAbAttr { private damageMultiplier: number; @@ -694,8 +693,6 @@ export interface TypeMultiplierAbAttrParams extends AugmentMoveInteractionAbAttr /** * Determines whether a Pokemon is immune to a move because of an ability. - * @see {@linkcode applyPreDefend} - * @see {@linkcode getCondition} */ export class TypeImmunityAbAttr extends PreDefendAbAttr { private immuneType: PokemonType | null; @@ -845,7 +842,6 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { /** * Attribute implementing the effects of {@link https://bulbapedia.bulbagarden.net/wiki/Tera_Shell_(Ability) | Tera Shell} * When the source is at full HP, incoming attacks will have a maximum 0.5x type effectiveness multiplier. - * @extends PreDefendAbAttr */ export class FullHpResistTypeAbAttr extends PreDefendAbAttr { /** @@ -1354,11 +1350,9 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { } } /** - * @description: This ability applies the Perish Song tag to the attacking pokemon + * This ability applies the Perish Song tag to the attacking pokemon * and the defending pokemon if the move makes physical contact and neither pokemon * already has the Perish Song tag. - * @class PostDefendPerishSongAbAttr - * @extends {PostDefendAbAttr} */ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr { private turns: number; @@ -1964,19 +1958,16 @@ export class PreAttackFieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostA /** * Boosts the power of a specific type of move for all Pokemon in the field. - * @extends PreAttackFieldMoveTypePowerBoostAbAttr */ export class FieldMoveTypePowerBoostAbAttr extends PreAttackFieldMoveTypePowerBoostAbAttr {} /** * Boosts the power of a specific type of move for the user and its allies. - * @extends PreAttackFieldMoveTypePowerBoostAbAttr */ export class UserFieldMoveTypePowerBoostAbAttr extends PreAttackFieldMoveTypePowerBoostAbAttr {} /** * Boosts the power of moves in specified categories. - * @extends FieldMovePowerBoostAbAttr */ export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr { /** @@ -2582,7 +2573,6 @@ export class PostIntimidateStatStageChangeAbAttr extends AbAttr { /** * Base class for defining all {@linkcode Ability} Attributes post summon - * @see {@linkcode applyPostSummon()} */ export abstract class PostSummonAbAttr extends AbAttr { /** Should the ability activate when gained in battle? This will almost always be true */ @@ -2622,7 +2612,7 @@ export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr { private arenaTags: ArenaTagType[]; /** - * @param arenaTags {@linkcode ArenaTagType[]} - the arena tags to be removed + * @param arenaTags - The arena tags to be removed */ constructor(arenaTags: ArenaTagType[]) { super(true); @@ -3183,7 +3173,6 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { /** * Reverts weather-based forms to their normal forms when the user is summoned. * Used by Cloud Nine and Air Lock. - * @extends PostSummonAbAttr */ export class PostSummonWeatherSuppressedFormChangeAbAttr extends PostSummonAbAttr { override canApply(_params: AbAttrBaseParams): boolean { @@ -3203,7 +3192,6 @@ export class PostSummonWeatherSuppressedFormChangeAbAttr extends PostSummonAbAtt /** * Triggers weather-based form change when summoned into an active weather. * Used by Forecast and Flower Gift. - * @extends PostSummonAbAttr */ export class PostSummonFormChangeByWeatherAbAttr extends PostSummonAbAttr { private ability: AbilityId; @@ -3385,7 +3373,6 @@ export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { /** * Attribute for form changes that occur on switching out - * @see {@linkcode applyPreSwitchOut} */ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr { private formFunc: (p: Pokemon) => number; @@ -4252,8 +4239,8 @@ function getAnticipationCondition(): AbAttrCondition { * Creates an ability condition that causes the ability to fail if that ability * has already been used by that pokemon that battle. It requires an ability to * be specified due to current limitations in how conditions on abilities work. - * @param {AbilityId} ability The ability to check if it's already been applied - * @returns {AbAttrCondition} The condition + * @param ability The ability to check if it's already been applied + * @returns The condition */ function getOncePerBattleCondition(ability: AbilityId): AbAttrCondition { return (pokemon: Pokemon) => { @@ -4644,7 +4631,7 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr { /** * @param procChance - function providing chance to restore an item - * @see {@linkcode createEatenBerry()} + * @see {@linkcode createEatenBerry} */ constructor(private procChance: (pokemon: Pokemon) => number) { super(); @@ -4909,7 +4896,6 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr { /** * Grabs the last failed Pokeball used * @sealed - * @see {@linkcode applyPostTurn} */ export class FetchBallAbAttr extends PostTurnAbAttr { override canApply({ simulated, pokemon }: AbAttrBaseParams): boolean { @@ -4999,7 +4985,6 @@ export class PostMoveUsedAbAttr extends AbAttr { /** * Triggers after a dance move is used either by the opponent or the player - * @extends PostMoveUsedAbAttr */ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { override canApply({ source, pokemon }: PostMoveUsedAbAttrParams): boolean { @@ -5058,7 +5043,6 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { /** * Triggers after the Pokemon loses or consumes an item - * @extends AbAttr */ export class PostItemLostAbAttr extends AbAttr { canApply(_params: Closed): boolean { @@ -5229,7 +5213,6 @@ type ArenaTrapCondition = (user: Pokemon, target: Pokemon) => boolean; /** * Base class for checking if a Pokemon is trapped by arena trap - * @extends AbAttr * @field {@linkcode arenaTrapCondition} Conditional for trapping abilities. * For example, Magnet Pull will only activate if opponent is Steel type. * @see {@linkcode applyCheckTrapped} @@ -5565,7 +5548,6 @@ export interface ReduceStatusEffectDurationAbAttrParams extends AbAttrBaseParams /** * Used by Early Bird, makes the pokemon wake up faster * @param statusEffect - The {@linkcode StatusEffect} to check for - * @see {@linkcode apply} * @sealed */ export class ReduceStatusEffectDurationAbAttr extends AbAttr { @@ -5861,8 +5843,6 @@ export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr { /** * Gives money to the user after the battle. - * - * @extends PostBattleAbAttr */ export class MoneyAbAttr extends PostBattleAbAttr { override canApply({ simulated, victory }: PostBattleAbAttrParams): boolean { @@ -5966,7 +5946,6 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr { /** * Base class for defining {@linkcode Ability} attributes before summon * (should use {@linkcode PostSummonAbAttr} for most ability) - * @see {@linkcode applyPreSummon()} */ export class PreSummonAbAttr extends AbAttr { private declare readonly _: never; @@ -6418,8 +6397,6 @@ export class PostDamageAbAttr extends AbAttr { * and its opponents, and determines whether a forced switch-out should occur. * * Used by Wimp Out and Emergency Exit - * - * @see {@linkcode applyPostDamage} * @sealed */ export class PostDamageForceSwitchAbAttr extends PostDamageAbAttr { @@ -7038,6 +7015,7 @@ export function initAbilities() { .attr(StatMultiplierAbAttr, Stat.SPATK, 1.5) .condition(getWeatherCondition(WeatherType.SUNNY, WeatherType.HARSH_SUN)), new Ability(AbilityId.QUICK_FEET, 4) + // TODO: This should ignore the speed drop, not manually undo it .conditionalAttr(pokemon => pokemon.status ? pokemon.status.effect === StatusEffect.PARALYSIS : false, StatMultiplierAbAttr, Stat.SPD, 2) .conditionalAttr(pokemon => !!pokemon.status || pokemon.hasAbility(AbilityId.COMATOSE), StatMultiplierAbAttr, Stat.SPD, 1.5), new Ability(AbilityId.NORMALIZE, 4) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index d19f2f7f478..22955e0a9ac 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -1132,7 +1132,7 @@ class ImprisonTag extends EntryHazardTag { /** * This applies the effects of Imprison to any opposing Pokemon that switch into the field while the source Pokemon is still active - * @param {Pokemon} pokemon the Pokemon Imprison is applied to + * @param pokemon the Pokemon Imprison is applied to * @returns `true` */ override activateTrap(pokemon: Pokemon): boolean { diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 54952b9d7fb..35a042249d8 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2192,7 +2192,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag { null, false, null, - true, + false, ); } @@ -2507,10 +2507,7 @@ export class RemovedTypeTag extends SerializableBattlerTag { } } -/** - * Battler tag for effects that ground the source, allowing Ground-type moves to hit them. - * @description `IGNORE_FLYING`: Persistent grounding effects (i.e. from Smack Down and Thousand Waves) - */ +/** Battler tag for effects that ground the source, allowing Ground-type moves to hit them. */ export class GroundedTag extends SerializableBattlerTag { public override readonly tagType = BattlerTagType.IGNORE_FLYING; constructor(tagType: BattlerTagType.IGNORE_FLYING, lapseType: BattlerTagLapseType, sourceMove: MoveId) { @@ -2518,11 +2515,7 @@ export class GroundedTag extends SerializableBattlerTag { } } -/** - * @description `ROOSTED`: Tag for temporary grounding if only source of ungrounding is flying and pokemon uses Roost. - * Roost removes flying type from a pokemon for a single turn. - */ - +/** Removes flying type from a pokemon for a single turn */ export class RoostedTag extends BattlerTag { private isBaseFlying: boolean; private isBasePureFlying: boolean; @@ -2601,7 +2594,7 @@ export class FormBlockDamageTag extends SerializableBattlerTag { /** * Applies the tag to the Pokémon. * Triggers a form change if the Pokémon is not in its defense form. - * @param {Pokemon} pokemon The Pokémon to which the tag is added. + * @param pokemon The Pokémon to which the tag is added. */ onAdd(pokemon: Pokemon): void { super.onAdd(pokemon); diff --git a/src/data/challenge.ts b/src/data/challenge.ts index a8ec92df57d..65faa900af7 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -1,5 +1,6 @@ import type { FixedBattleConfig } from "#app/battle"; import { getRandomTrainerFunc } from "#app/battle"; +import { globalScene } from "#app/global-scene"; import { defaultStarterSpeciesAndEvolutions } from "#balance/pokemon-evolutions"; import { speciesStarterCosts } from "#balance/starters"; import type { PokemonSpecies } from "#data/pokemon-species"; @@ -12,6 +13,7 @@ import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; import { ModifierTier } from "#enums/modifier-tier"; import { MoveId } from "#enums/move-id"; import type { MoveSourceType } from "#enums/move-source-type"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Nature } from "#enums/nature"; import { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; @@ -21,9 +23,10 @@ import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon"; import { Trainer } from "#field/trainer"; import type { ModifierTypeOption } from "#modifiers/modifier-type"; import { PokemonMove } from "#moves/pokemon-move"; -import type { DexAttrProps, GameData, StarterDataEntry } from "#system/game-data"; +import type { GameData } from "#system/game-data"; import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data"; import type { DexEntry } from "#types/dex-data"; +import type { DexAttrProps, StarterDataEntry } from "#types/save-data"; import { type BooleanHolder, isBetween, type NumberHolder, randSeedItem } from "#utils/common"; import { deepCopy } from "#utils/data"; import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils"; @@ -56,7 +59,7 @@ export abstract class Challenge { } /** - * @param id {@link Challenges} The enum value for the challenge + * @param id - The enum value for the challenge */ constructor(id: Challenges, maxValue: number = Number.MAX_SAFE_INTEGER) { this.id = id; @@ -85,9 +88,9 @@ export abstract class Challenge { } /** - * Used for unlockable challenges to check if they're unlocked. - * @param data {@link GameData} The save data. - * @returns {@link boolean} Whether this challenge is unlocked. + * Check if an unlockable challenge is unlocked + * @param data - The save data + * @returns Whether this challenge is unlocked */ isUnlocked(data: GameData): boolean { return this.conditions.every(f => f(data)); @@ -95,8 +98,8 @@ export abstract class Challenge { /** * Adds an unlock condition to this challenge. - * @param condition {@link ChallengeCondition} The condition to add. - * @returns {@link Challenge} This challenge + * @param condition - The condition to add + * @returns This challenge */ condition(condition: ChallengeCondition): Challenge { this.conditions.push(condition); @@ -105,7 +108,7 @@ export abstract class Challenge { } /** - * @returns {@link string} The localised name of this challenge. + * @returns The localised name of this challenge. */ getName(): string { return i18next.t(`challenges:${this.geti18nKey()}.name`); @@ -132,7 +135,7 @@ export abstract class Challenge { /** * Increase the value of the challenge - * @returns {@link boolean} Returns true if the value changed + * @returns Returns true if the value changed */ increaseValue(): boolean { if (this.value < this.maxValue) { @@ -144,7 +147,7 @@ export abstract class Challenge { /** * Decrease the value of the challenge - * @returns {@link boolean} Returns true if the value changed + * @returns Returns true if the value changed */ decreaseValue(): boolean { if (this.value > 0) { @@ -163,7 +166,7 @@ export abstract class Challenge { /** * Decrease the severity of the challenge - * @returns {@link boolean} Returns true if the value changed + * @returns Returns true if the value changed */ decreaseSeverity(): boolean { if (this.severity > 0) { @@ -175,7 +178,7 @@ export abstract class Challenge { /** * Increase the severity of the challenge - * @returns {@link boolean} Returns true if the value changed + * @returns Returns true if the value changed */ increaseSeverity(): boolean { if (this.severity < this.maxSeverity) { @@ -187,7 +190,7 @@ export abstract class Challenge { /** * Gets the "difficulty" value of this challenge. - * @returns {@link integer} The difficulty value. + * @returns The difficulty value. */ getDifficulty(): number { return this.value; @@ -195,7 +198,7 @@ export abstract class Challenge { /** * Gets the minimum difficulty added by this challenge. - * @returns {@link integer} The difficulty value. + * @returns The difficulty value. */ getMinDifficulty(): number { return 0; @@ -203,7 +206,7 @@ export abstract class Challenge { /** * Clones a challenge, either from another challenge or json. Chainable. - * @param source The source challenge or json. + * @param _source - The source challenge or json. * @returns This challenge. */ static loadChallenge(_source: Challenge | any): Challenge { @@ -212,10 +215,10 @@ export abstract class Challenge { /** * An apply function for STARTER_CHOICE challenges. Derived classes should alter this. - * @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of. - * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. - * @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The Pokémon to check the validity of + * @param _valid - Holder for whether the Pokémon is valid or not + * @param _dexAttr - The dex attributes of the Pokémon + * @returns Whether this function did anything. */ applyStarterChoice(_pokemon: PokemonSpecies, _valid: BooleanHolder, _dexAttr: DexAttrProps): boolean { return false; @@ -223,8 +226,8 @@ export abstract class Challenge { /** * An apply function for STARTER_POINTS challenges. Derived classes should alter this. - * @param _points {@link NumberHolder} The amount of points you have available. - * @returns {@link boolean} Whether this function did anything. + * @param _points - Holder for amount of starter points the user has to spend + * @returns Whether this function did anything */ applyStarterPoints(_points: NumberHolder): boolean { return false; @@ -232,9 +235,9 @@ export abstract class Challenge { /** * An apply function for STARTER_COST challenges. Derived classes should alter this. - * @param _species {@link SpeciesId} The pokemon to change the cost of. - * @param _cost {@link NumberHolder} The cost of the starter. - * @returns {@link boolean} Whether this function did anything. + * @param _species - The pokémon to change the cost of + * @param _cost - Holder for the cost of the starter Pokémon + * @returns Whether this function did anything. */ applyStarterCost(_species: SpeciesId, _cost: NumberHolder): boolean { return false; @@ -242,8 +245,8 @@ export abstract class Challenge { /** * An apply function for STARTER_SELECT_MODIFY challenges. Derived classes should alter this. - * @param _pokemon {@link Pokemon} The starter pokemon to modify. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The starter Pokémon to modify. + * @returns Whether this function did anything. */ applyStarterSelectModify(_speciesId: SpeciesId, _dexEntry: DexEntry, _starterDataEntry: StarterDataEntry): boolean { return false; @@ -251,8 +254,8 @@ export abstract class Challenge { /** * An apply function for STARTER_MODIFY challenges. Derived classes should alter this. - * @param _pokemon {@link Pokemon} The starter pokemon to modify. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The starter Pokémon to modify. + * @returns Whether this function did anything. */ applyStarterModify(_pokemon: Pokemon): boolean { return false; @@ -260,9 +263,9 @@ export abstract class Challenge { /** * An apply function for POKEMON_IN_BATTLE challenges. Derived classes should alter this. - * @param _pokemon {@link Pokemon} The pokemon to check the validity of. - * @param _valid {@link BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The Pokémon to check the validity of + * @param _valid - Holds a boolean that will be set to false if the Pokémon isn't allowed + * @returns Whether this function did anything */ applyPokemonInBattle(_pokemon: Pokemon, _valid: BooleanHolder): boolean { return false; @@ -270,9 +273,9 @@ export abstract class Challenge { /** * An apply function for FIXED_BATTLE challenges. Derived classes should alter this. - * @param _waveIndex {@link Number} The current wave index. - * @param _battleConfig {@link FixedBattleConfig} The battle config to modify. - * @returns {@link boolean} Whether this function did anything. + * @param _waveIndex The current wave index + * @param _battleConfig - The battle config to modify + * @returns Whether this function did anything */ applyFixedBattle(_waveIndex: number, _battleConfig: FixedBattleConfig): boolean { return false; @@ -280,8 +283,8 @@ export abstract class Challenge { /** * An apply function for TYPE_EFFECTIVENESS challenges. Derived classes should alter this. - * @param _effectiveness {@linkcode NumberHolder} The current effectiveness of the move. - * @returns Whether this function did anything. + * @param _effectiveness - The current effectiveness of the move + * @returns Whether this function did anything */ applyTypeEffectiveness(_effectiveness: NumberHolder): boolean { return false; @@ -289,11 +292,11 @@ export abstract class Challenge { /** * An apply function for AI_LEVEL challenges. Derived classes should alter this. - * @param _level {@link NumberHolder} The generated level. - * @param _levelCap {@link Number} The current level cap. - * @param _isTrainer {@link Boolean} Whether this is a trainer pokemon. - * @param _isBoss {@link Boolean} Whether this is a non-trainer boss pokemon. - * @returns {@link boolean} Whether this function did anything. + * @param _level - The generated level. + * @param _levelCap - The current level cap. + * @param _isTrainer - Whether this is a trainer Pokémon + * @param _isBoss - Whether this is a non-trainer boss Pokémon + * @returns - Whether this function did anything */ applyLevelChange(_level: NumberHolder, _levelCap: number, _isTrainer: boolean, _isBoss: boolean): boolean { return false; @@ -301,9 +304,9 @@ export abstract class Challenge { /** * An apply function for AI_MOVE_SLOTS challenges. Derived classes should alter this. - * @param pokemon {@link Pokemon} The pokemon that is being considered. - * @param moveSlots {@link NumberHolder} The amount of move slots. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The Pokémon that is being considered + * @param _moveSlots - The amount of move slots + * @returns Whether this function did anything */ applyMoveSlot(_pokemon: Pokemon, _moveSlots: NumberHolder): boolean { return false; @@ -311,9 +314,9 @@ export abstract class Challenge { /** * An apply function for PASSIVE_ACCESS challenges. Derived classes should alter this. - * @param pokemon {@link Pokemon} The pokemon to change. - * @param hasPassive {@link BooleanHolder} Whether it should have its passive. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - The Pokémon to change + * @param _hasPassive - Whether it should have its passive + * @returns Whether this function did anything */ applyPassiveAccess(_pokemon: Pokemon, _hasPassive: BooleanHolder): boolean { return false; @@ -321,7 +324,7 @@ export abstract class Challenge { /** * An apply function for GAME_MODE_MODIFY challenges. Derived classes should alter this. - * @returns {@link boolean} Whether this function did anything. + * @returns Whether this function did anything */ applyGameModeModify(): boolean { return false; @@ -329,11 +332,11 @@ export abstract class Challenge { /** * An apply function for MOVE_ACCESS. Derived classes should alter this. - * @param _pokemon {@link Pokemon} What pokemon would learn the move. - * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. - * @param _move {@link MoveId} The move in question. - * @param _level {@link NumberHolder} The level threshold for access. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - What Pokémon would learn the move + * @param _moveSource - What source the Pokémon would get the move from + * @param _move - The move in question + * @param _level - The level threshold for access + * @returns Whether this function did anything */ applyMoveAccessLevel(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _level: NumberHolder): boolean { return false; @@ -341,21 +344,21 @@ export abstract class Challenge { /** * An apply function for MOVE_WEIGHT. Derived classes should alter this. - * @param _pokemon {@link Pokemon} What pokemon would learn the move. - * @param _moveSource {@link MoveSourceType} What source the pokemon would get the move from. - * @param _move {@link MoveId} The move in question. - * @param _weight {@link NumberHolder} The base weight of the move - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - What Pokémon would learn the move + * @param _moveSource - What source the Pokémon would get the move from + * @param _move - The move in question. + * @param _weight - The base weight of the move + * @returns Whether this function did anything */ - applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _level: NumberHolder): boolean { + applyMoveWeight(_pokemon: Pokemon, _moveSource: MoveSourceType, _move: MoveId, _weight: NumberHolder): boolean { return false; } /** * An apply function for FlipStats. Derived classes should alter this. - * @param _pokemon {@link Pokemon} What pokemon would learn the move. - * @param _baseStats What are the stats to flip. - * @returns {@link boolean} Whether this function did anything. + * @param _pokemon - What Pokémon would learn the move + * @param _baseStats What are the stats to flip + * @returns Whether this function did anything */ applyFlipStat(_pokemon: Pokemon, _baseStats: number[]) { return false; @@ -381,9 +384,9 @@ export abstract class Challenge { /** * An apply function for POKEMON_ADD_TO_PARTY. Derived classes should alter this. - * @param _pokemon - The pokemon being caught - * @param _status - Whether the pokemon can be added to the party or not - * @return Whether this function did anything + * @param _pokemon - The Pokémon being caught + * @param _status - Whether the Pokémon can be added to the party or not + * @returns Whether this function did anything */ applyPokemonAddToParty(_pokemon: EnemyPokemon, _status: BooleanHolder): boolean { return false; @@ -391,8 +394,8 @@ export abstract class Challenge { /** * An apply function for POKEMON_FUSION. Derived classes should alter this. - * @param _pokemon - The pokemon being checked - * @param _status - Whether the selected pokemon is allowed to fuse or not + * @param _pokemon - The Pokémon being checked + * @param _status - Whether the selected Pokémon is allowed to fuse or not * @returns Whether this function did anything */ applyPokemonFusion(_pokemon: PlayerPokemon, _status: BooleanHolder): boolean { @@ -670,10 +673,7 @@ export class SingleGenerationChallenge extends Challenge { return false; } - /** - * @overrides - */ - getDifficulty(): number { + override getDifficulty(): number { return this.value > 0 ? 1 : 0; } @@ -756,10 +756,7 @@ export class SingleTypeChallenge extends Challenge { return false; } - /** - * @overrides - */ - getDifficulty(): number { + override getDifficulty(): number { return this.value > 0 ? 1 : 0; } @@ -1081,7 +1078,12 @@ export class LimitedCatchChallenge extends Challenge { override applyPokemonAddToParty(pokemon: EnemyPokemon, status: BooleanHolder): boolean { if (status.value) { - status.value = pokemon.metWave % 10 === 1; + const isTeleporter = + globalScene.currentBattle.mysteryEncounter?.encounterType === MysteryEncounterType.TELEPORTING_HIJINKS + && globalScene.currentBattle.mysteryEncounter.selectedOption + !== globalScene.currentBattle.mysteryEncounter.options[2]; // don't allow catch when not choosing biome change option + const isFirstWave = pokemon.metWave % 10 === 1; + status.value = isTeleporter || isFirstWave; return true; } return false; diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts index a0d3358ecb0..addaebdd238 100644 --- a/src/data/daily-run.ts +++ b/src/data/daily-run.ts @@ -6,7 +6,7 @@ import { PokemonSpecies } from "#data/pokemon-species"; import { BiomeId } from "#enums/biome-id"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { SpeciesId } from "#enums/species-id"; -import type { Starter } from "#ui/handlers/starter-select-ui-handler"; +import type { Starter } from "#ui/starter-select-ui-handler"; import { isNullOrUndefined, randSeedGauss, randSeedInt, randSeedItem } from "#utils/common"; import { getEnumValues } from "#utils/enums"; import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils"; diff --git a/src/data/egg-hatch-data.ts b/src/data/egg-hatch-data.ts index e78dc4d7984..efe06d5a504 100644 --- a/src/data/egg-hatch-data.ts +++ b/src/data/egg-hatch-data.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import type { PlayerPokemon } from "#field/pokemon"; -import type { StarterDataEntry } from "#system/game-data"; import type { DexEntry } from "#types/dex-data"; +import type { StarterDataEntry } from "#types/save-data"; /** * Stores data associated with a specific egg and the hatched pokemon diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 77096c038a9..9de58770467 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -644,9 +644,9 @@ export abstract class Move implements Localizable { * will not consider {@linkcode AbilityId.WIND_RIDER | Wind Rider }. * * To simply check whether the move has a flag, use {@linkcode hasFlag}. - * @param flag {@linkcode MoveFlags} MoveFlag to check on user and/or target - * @param user {@linkcode Pokemon} the Pokemon using the move - * @param target {@linkcode Pokemon} the Pokemon receiving the move + * @param flag - MoveFlag to check on user and/or target + * @param user - the Pokemon using the move + * @param target - the Pokemon receiving the move * @param isFollowUp (defaults to `false`) `true` if the move was used as a follow up * @returns boolean * @see {@linkcode hasFlag} @@ -1133,11 +1133,7 @@ function ChargeMove(Base: TBase, nameAppend: string) { export class ChargingAttackMove extends ChargeMove(AttackMove, "ChargingAttackMove") {} export class ChargingSelfStatusMove extends ChargeMove(SelfStatusMove, "ChargingSelfStatusMove") {} -/** - * Base class defining all {@linkcode Move} Attributes - * @abstract - * @see {@linkcode apply} - */ +/** Base class defining all {@linkcode Move} Attributes */ export abstract class MoveAttr { /** Should this {@linkcode Move} target the user? */ public selfTarget: boolean; @@ -1233,8 +1229,6 @@ interface MoveEffectAttrOptions { /** * Base class defining all Move Effect Attributes - * @extends MoveAttr - * @see {@linkcode apply} */ export class MoveEffectAttr extends MoveAttr { /** @@ -1450,7 +1444,6 @@ export class PreMoveMessageAttr extends MoveAttr { * Attribute for moves that can be conditionally interrupted to be considered to * have failed before their "useMove" message is displayed. Currently used by * Focus Punch. - * @extends MoveAttr */ export class PreUseInterruptAttr extends MoveAttr { protected message: string | MoveMessageFunc; @@ -1494,7 +1487,6 @@ export class PreUseInterruptAttr extends MoveAttr { /** * Attribute for Status moves that take attack type effectiveness * into consideration (i.e. {@linkcode https://bulbapedia.bulbagarden.net/wiki/Thunder_Wave_(move) | Thunder Wave}) - * @extends MoveAttr */ export class RespectAttackTypeImmunityAttr extends MoveAttr { } @@ -1778,9 +1770,7 @@ export class RecoilAttr extends MoveEffectAttr { /** * Attribute used for moves which self KO the user regardless if the move hits a target - * @extends MoveEffectAttr - * @see {@linkcode apply} - **/ + */ export class SacrificialAttr extends MoveEffectAttr { constructor() { super(true, { trigger: MoveEffectTrigger.POST_TARGET }); @@ -1811,9 +1801,7 @@ export class SacrificialAttr extends MoveEffectAttr { /** * Attribute used for moves which self KO the user but only if the move hits a target - * @extends MoveEffectAttr - * @see {@linkcode apply} - **/ + */ export class SacrificialAttrOnHit extends MoveEffectAttr { constructor() { super(true); @@ -1850,8 +1838,6 @@ export class SacrificialAttrOnHit extends MoveEffectAttr { /** * Attribute used for moves which cut the user's Max HP in half. * Triggers using {@linkcode MoveEffectTrigger.POST_TARGET}. - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class HalfSacrificialAttr extends MoveEffectAttr { constructor() { @@ -1951,8 +1937,6 @@ export class AddSubstituteAttr extends MoveEffectAttr { /** * Heals the user or target by {@linkcode healRatio} depending on the value of {@linkcode selfTarget} - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class HealAttr extends MoveEffectAttr { constructor( @@ -2041,8 +2025,6 @@ export class RestAttr extends HealAttr { /** * Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class PartyStatusCureAttr extends MoveEffectAttr { /** Message to display after using move */ @@ -2101,7 +2083,6 @@ export class PartyStatusCureAttr extends MoveEffectAttr { /** * Applies damage to the target's ally equal to 1/16 of that ally's max HP. - * @extends MoveEffectAttr */ export class FlameBurstAttr extends MoveEffectAttr { constructor() { @@ -2190,8 +2171,6 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr { /** * Attribute used for moves which ignore type-based debuffs from weather, namely Hydro Steam. * Called during damage calculation after getting said debuff from getAttackTypeMultiplier in the Pokemon class. - * @extends MoveAttr - * @see {@linkcode apply} */ export class IgnoreWeatherTypeDebuffAttr extends MoveAttr { /** The {@linkcode WeatherType} this move ignores */ @@ -2270,8 +2249,6 @@ export class SandHealAttr extends WeatherHealAttr { /** * Heals the target or the user by either {@linkcode normalHealRatio} or {@linkcode boostedHealRatio} * depending on the evaluation of {@linkcode condition} - * @extends HealAttr - * @see {@linkcode apply} */ export class BoostHealAttr extends HealAttr { /** Healing received when {@linkcode condition} is false */ @@ -2304,8 +2281,6 @@ export class BoostHealAttr extends HealAttr { /** * Heals the target only if it is the ally - * @extends HealAttr - * @see {@linkcode apply} */ export class HealOnAllyAttr extends HealAttr { override canApply(user: Pokemon, target: Pokemon, _move: Move, _args?: any[]): boolean { @@ -2324,9 +2299,6 @@ export class HealOnAllyAttr extends HealAttr { /** * Heals user as a side effect of a move that hits a target. * Healing is based on {@linkcode healRatio} * the amount of damage dealt or a stat of the target. - * @extends MoveEffectAttr - * @see {@linkcode apply} - * @see {@linkcode getUserBenefitScore} */ // TODO: Make Strength Sap its own attribute that extends off of this one export class HitHealAttr extends MoveEffectAttr { @@ -2396,8 +2368,6 @@ export class HitHealAttr extends MoveEffectAttr { * Attribute used for moves that change priority in a turn given a condition, * e.g. Grassy Glide * Called when move order is calculated in {@linkcode TurnStartPhase}. - * @extends MoveAttr - * @see {@linkcode apply} */ export class IncrementMovePriorityAttr extends MoveAttr { /** The condition for a move's priority being incremented */ @@ -2433,10 +2403,8 @@ export class IncrementMovePriorityAttr extends MoveAttr { /** * Attribute used for attack moves that hit multiple times per use, e.g. Bullet Seed. * + * @remarks * Applied at the beginning of {@linkcode MoveEffectPhase}. - * - * @extends MoveAttr - * @see {@linkcode apply} */ export class MultiHitAttr extends MoveAttr { /** This move's intrinsic multi-hit type. It should never be modified. */ @@ -2946,8 +2914,6 @@ export class StealEatBerryAttr extends EatBerryAttr { /** * Move attribute that signals that the move should cure a status effect - * @extends MoveEffectAttr - * @see {@linkcode apply()} */ export class HealStatusEffectAttr extends MoveEffectAttr { /** List of Status Effects to cure */ @@ -3030,8 +2996,6 @@ export class BypassSleepAttr extends MoveAttr { /** * Attribute used for moves that bypass the burn damage reduction of physical moves, currently only facade * Called during damage calculation - * @extends MoveAttr - * @see {@linkcode apply} */ export class BypassBurnDamageReductionAttr extends MoveAttr { /** Prevents the move's damage from being reduced by burn @@ -3140,7 +3104,6 @@ export class OneHitKOAttr extends MoveAttr { /** * Attribute that allows charge moves to resolve in 1 turn under a given condition. * Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`. - * @extends MoveAttr */ export class InstantChargeAttr extends MoveAttr { /** The condition in which the move with this attribute instantly charges */ @@ -3177,7 +3140,6 @@ export class InstantChargeAttr extends MoveAttr { /** * Attribute that allows charge moves to resolve in 1 turn while specific {@linkcode WeatherType | Weather} * is active. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`. - * @extends InstantChargeAttr */ export class WeatherInstantChargeAttr extends InstantChargeAttr { constructor(weatherTypes: WeatherType[]) { @@ -3307,7 +3269,6 @@ export class WishAttr extends MoveEffectAttr { /** * Attribute that cancels the associated move's effects when set to be combined with the user's ally's * subsequent move this turn. Used for Grass Pledge, Water Pledge, and Fire Pledge. - * @extends OverrideMoveEffectAttr */ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr { constructor() { @@ -3362,7 +3323,6 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr { /** * Set of optional parameters that may be applied to stat stage changing effects - * @extends MoveEffectAttrOptions * @see {@linkcode StatStageChangeAttr} */ interface StatStageChangeAttrOptions extends MoveEffectAttrOptions { @@ -3379,9 +3339,6 @@ interface StatStageChangeAttrOptions extends MoveEffectAttrOptions { * @param stages How many stages to change the stat(s) by, [-6, 6] * @param selfTarget `true` if the move is self-targetting * @param options {@linkcode StatStageChangeAttrOptions} Container for any optional parameters for this attribute. - * - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class StatStageChangeAttr extends MoveEffectAttr { public stats: BattleStat[]; @@ -3812,8 +3769,6 @@ export class ResetStatsAttr extends MoveEffectAttr { /** * Attribute used for status moves, specifically Heart, Guard, and Power Swap, * that swaps the user's and target's corresponding stat stages. - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class SwapStatStagesAttr extends MoveEffectAttr { /** The stat stages to be swapped between the user and the target */ @@ -4101,8 +4056,6 @@ export class WeightPowerAttr extends VariablePowerAttr { /** * Attribute used for Electro Ball move. - * @extends VariablePowerAttr - * @see {@linkcode apply} **/ export class ElectroBallPowerAttr extends VariablePowerAttr { /** @@ -4136,8 +4089,6 @@ export class ElectroBallPowerAttr extends VariablePowerAttr { /** * Attribute used for Gyro Ball move. - * @extends VariablePowerAttr - * @see {@linkcode apply} **/ export class GyroBallPowerAttr extends VariablePowerAttr { /** @@ -4393,11 +4344,11 @@ const countPositiveStatStages = (pokemon: Pokemon): number => { export class PositiveStatStagePowerAttr extends VariablePowerAttr { /** - * @param {Pokemon} user The pokemon that is being used to calculate the amount of positive stats - * @param {Pokemon} target N/A - * @param {Move} move N/A - * @param {any[]} args The argument for VariablePowerAttr, accumulates and sets the amount of power multiplied by stats - * @returns {boolean} Returns true if attribute is applied + * @param user The pokemon that is being used to calculate the amount of positive stats + * @param target N/A + * @param move N/A + * @param args The argument for VariablePowerAttr, accumulates and sets the amount of power multiplied by stats + * @returns Returns true if attribute is applied */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const positiveStatStages: number = countPositiveStatStages(user); @@ -4417,10 +4368,10 @@ export class PunishmentPowerAttr extends VariablePowerAttr { private PUNISHMENT_MAX_BASE_POWER = 200; /** - * @param {Pokemon} user N/A - * @param {Pokemon} target The pokemon that the move is being used against, as well as calculating the stats for the min/max base power - * @param {Move} move N/A - * @param {any[]} args The value that is being changed due to VariablePowerAttr + * @param user N/A + * @param target The pokemon that the move is being used against, as well as calculating the stats for the min/max base power + * @param move N/A + * @param args The value that is being changed due to VariablePowerAttr * @returns Returns true if attribute is applied */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -4536,8 +4487,6 @@ const hasStockpileStacksCondition: MoveConditionFunc = (user) => { /** * Attribute used for multi-hit moves that increase power in increments of the * move's base power for each hit, namely Triple Kick and Triple Axel. - * @extends VariablePowerAttr - * @see {@linkcode apply} */ export class MultiHitPowerIncrementAttr extends VariablePowerAttr { /** The max number of base power increments allowed for this move */ @@ -4574,8 +4523,6 @@ export class MultiHitPowerIncrementAttr extends VariablePowerAttr { * Attribute used for moves that double in power if the given move immediately * preceded the move applying the attribute, namely Fusion Flare and * Fusion Bolt. - * @extends VariablePowerAttr - * @see {@linkcode apply} */ export class LastMoveDoublePowerAttr extends VariablePowerAttr { /** The move that must precede the current move */ @@ -4678,7 +4625,6 @@ export class CombinedPledgeStabBoostAttr extends MoveAttr { /** * Variable Power attribute for {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}. * Doubles power if another Pokemon has previously selected Round this turn. - * @extends VariablePowerAttr */ export class RoundPowerAttr extends VariablePowerAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: [NumberHolder]): boolean { @@ -4696,8 +4642,6 @@ export class RoundPowerAttr extends VariablePowerAttr { * Attribute for the "combo" effect of {@link https://bulbapedia.bulbagarden.net/wiki/Round_(move) | Round}. * Preempts the next move in the turn order with the first instance of any Pokemon * using Round. Also marks the Pokemon using the cued Round to double the move's power. - * @extends MoveEffectAttr - * @see {@linkcode RoundPowerAttr} */ export class CueNextRoundAttr extends MoveEffectAttr { constructor() { @@ -4899,8 +4843,6 @@ export class StormAccuracyAttr extends VariableAccuracyAttr { /** * Attribute used for moves which never miss * against Pokemon with the {@linkcode BattlerTagType.MINIMIZED} - * @extends VariableAccuracyAttr - * @see {@linkcode apply} */ export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr { /** @@ -4973,9 +4915,8 @@ export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr { * Attribute used for tera moves that change category based on the user's Atk and SpAtk stats * Note: Currently, `getEffectiveStat` does not ignore all abilities that affect stats except those * with the attribute of `StatMultiplierAbAttr` - * TODO: Remove the `.partial()` tag from Tera Blast and Tera Starstorm when the above issue is resolved - * @extends VariableMoveCategoryAttr */ +// TODO: Remove the `.partial()` tag from Tera Blast and Tera Starstorm when the above issue is resolved export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const category = (args[0] as NumberHolder); @@ -4992,7 +4933,6 @@ export class TeraMoveCategoryAttr extends VariableMoveCategoryAttr { /** * Increases the power of Tera Blast if the user is Terastallized into Stellar type - * @extends VariablePowerAttr */ export class TeraBlastPowerAttr extends VariablePowerAttr { /** @@ -5019,8 +4959,6 @@ export class TeraBlastPowerAttr extends VariablePowerAttr { /** * Change the move category to status when used on the ally - * @extends VariableMoveCategoryAttr - * @see {@linkcode apply} */ export class StatusCategoryOnAllyAttr extends VariableMoveCategoryAttr { /** @@ -5252,8 +5190,6 @@ export class WeatherBallTypeAttr extends VariableMoveTypeAttr { /** * Changes the move's type to match the current terrain. * Has no effect if the user is not grounded. - * @extends VariableMoveTypeAttr - * @see {@linkcode apply} */ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr { /** @@ -5301,7 +5237,6 @@ export class TerrainPulseTypeAttr extends VariableMoveTypeAttr { /** * Changes type based on the user's IVs - * @extends VariableMoveTypeAttr */ export class HiddenPowerTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -5329,7 +5264,6 @@ export class HiddenPowerTypeAttr extends VariableMoveTypeAttr { /** * Changes the type of Tera Blast to match the user's tera type - * @extends VariableMoveTypeAttr */ export class TeraBlastTypeAttr extends VariableMoveTypeAttr { /** @@ -5356,7 +5290,6 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr { /** * Attribute used for Tera Starstorm that changes the move type to Stellar - * @extends VariableMoveTypeAttr */ export class TeraStarstormTypeAttr extends VariableMoveTypeAttr { /** @@ -5402,7 +5335,6 @@ export class MatchUserTypeAttr extends VariableMoveTypeAttr { /** * Changes the type of a Pledge move based on the Pledge move combined with it. - * @extends VariableMoveTypeAttr */ export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -5540,10 +5472,10 @@ export class SheerColdAccuracyAttr extends OneHitKOAccuracyAttr { /** * Changes the normal One Hit KO Accuracy Attr to implement the Gen VII changes, * where if the user is Ice-Type, it has more accuracy. - * @param {Pokemon} user Pokemon that is using the move; checks the Pokemon's level. - * @param {Pokemon} target Pokemon that is receiving the move; checks the Pokemon's level. - * @param {Move} move N/A - * @param {any[]} args Uses the accuracy argument, allowing to change it from either 0 if it doesn't pass + * @param user Pokemon that is using the move; checks the Pokemon's level. + * @param target Pokemon that is receiving the move; checks the Pokemon's level. + * @param move N/A + * @param args Uses the accuracy argument, allowing to change it from either 0 if it doesn't pass * the first if/else, or 30/20 depending on the type of the user Pokemon. * @returns Returns true if move is successful, false if misses. */ @@ -5658,7 +5590,6 @@ export class FrenzyAttr extends MoveEffectAttr { /** * Attribute that grants {@link https://bulbapedia.bulbagarden.net/wiki/Semi-invulnerable_turn | semi-invulnerability} to the user during * the associated move's charging phase. Should only be used for {@linkcode ChargingMove | ChargingMoves} as a `chargeAttr`. - * @extends MoveEffectAttr */ export class SemiInvulnerableAttr extends MoveEffectAttr { /** The type of {@linkcode SemiInvulnerableTag} to grant to the user */ @@ -5812,7 +5743,6 @@ export class YawnAttr extends AddBattlerTagAttr { /** * Adds a {@link https://bulbapedia.bulbagarden.net/wiki/Seeding | Seeding} effect to the target * as seen with Leech Seed and Sappy Seed. - * @extends AddBattlerTagAttr */ export class LeechSeedAttr extends AddBattlerTagAttr { constructor() { @@ -5822,7 +5752,6 @@ export class LeechSeedAttr extends AddBattlerTagAttr { /** * Adds the appropriate battler tag for Smack Down and Thousand arrows - * @extends AddBattlerTagAttr */ export class FallDownAttr extends AddBattlerTagAttr { constructor() { @@ -5847,7 +5776,6 @@ export class FallDownAttr extends AddBattlerTagAttr { /** * Adds the appropriate battler tag for Gulp Missile when Surf or Dive is used. - * @extends MoveEffectAttr */ export class GulpMissileTagAttr extends MoveEffectAttr { constructor() { @@ -5887,7 +5815,6 @@ export class GulpMissileTagAttr extends MoveEffectAttr { /** * Attribute to implement Jaw Lock's linked trapping effect between the user and target - * @extends AddBattlerTagAttr */ export class JawLockAttr extends AddBattlerTagAttr { constructor() { @@ -6053,7 +5980,6 @@ export class ProtectAttr extends AddBattlerTagAttr { /** * Attribute to remove all Substitutes from the field. - * @extends MoveEffectAttr * @see {@link https://bulbapedia.bulbagarden.net/wiki/Tidy_Up_(move) | Tidy Up} * @see {@linkcode SubstituteTag} */ @@ -6085,7 +6011,6 @@ export class RemoveAllSubstitutesAttr extends MoveEffectAttr { * Attribute used when a move can deal damage to {@linkcode BattlerTagType} * Moves that always hit but do not deal double damage: Thunder, Fissure, Sky Uppercut, * Smack Down, Hurricane, Thousand Arrows - * @extends MoveAttr */ export class HitsTagAttr extends MoveAttr { /** The {@linkcode BattlerTagType} this move hits */ @@ -6199,8 +6124,6 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr { /** * Attribute used for Stone Axe and Ceaseless Edge. * Applies the given ArenaTrapTag when move is used. - * @extends AddArenaTagAttr - * @see {@linkcode apply} */ export class AddArenaTrapTagHitAttr extends AddArenaTagAttr { /** @@ -6293,10 +6216,7 @@ export class RemoveScreensAttr extends MoveEffectAttr { } } -/*Swaps arena effects between the player and enemy side - * @extends MoveEffectAttr - * @see {@linkcode apply} -*/ +/** Swaps arena effects between the player and enemy side */ export class SwapArenaTagsAttr extends MoveEffectAttr { public SwapTags: ArenaTagType[]; @@ -6362,8 +6282,6 @@ export class AddPledgeEffectAttr extends AddArenaTagAttr { /** * Attribute used for Revival Blessing. - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class RevivalBlessingAttr extends MoveEffectAttr { constructor() { @@ -6428,7 +6346,6 @@ export class RevivalBlessingAttr extends MoveEffectAttr { } } - export class ForceSwitchOutAttr extends MoveEffectAttr { constructor( private selfSwitch: boolean = false, @@ -6787,7 +6704,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr { /** * Retrieves a type from the current terrain * @param terrainType {@linkcode TerrainType} - * @returns {@linkcode Type} + * @returns */ private getTypeForTerrain(terrainType: TerrainType): PokemonType { switch (terrainType) { @@ -6808,7 +6725,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr { /** * Retrieves a type from the current biome * @param biomeType {@linkcode BiomeId} - * @returns {@linkcode Type} + * @returns */ private getTypeForBiome(biomeType: BiomeId): PokemonType { switch (biomeType) { @@ -6871,7 +6788,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr { } } -/** +/** * Attribute to override the target's current types to the given type. * Used by {@linkcode MoveId.SOAK} and {@linkcode MoveId.MAGIC_POWDER}. */ @@ -6941,8 +6858,6 @@ export class FirstMoveTypeAttr extends MoveEffectAttr { /** * Attribute used to call a move. * Used by other move attributes: {@linkcode RandomMoveAttr}, {@linkcode RandomMovesetMoveAttr}, {@linkcode CopyMoveAttr} - * @see {@linkcode apply} for move call - * @extends OverrideMoveEffectAttr */ class CallMoveAttr extends OverrideMoveEffectAttr { protected invalidMoves: ReadonlySet; @@ -6974,8 +6889,6 @@ class CallMoveAttr extends OverrideMoveEffectAttr { /** * Attribute used to call a random move. * Used for {@linkcode MoveId.METRONOME} - * @see {@linkcode apply} for move selection and move call - * @extends CallMoveAttr to call a selected move */ export class RandomMoveAttr extends CallMoveAttr { constructor(invalidMoves: ReadonlySet) { @@ -7023,8 +6936,6 @@ export class RandomMoveAttr extends CallMoveAttr { * Fails if the user has no callable moves. * * Invalid moves are indicated by what is passed in to invalidMoves: {@linkcode invalidAssistMoves} or {@linkcode invalidSleepTalkMoves} - * @extends RandomMoveAttr to use the callMove function on a moveId - * @see {@linkcode getCondition} for move selection */ export class RandomMovesetMoveAttr extends CallMoveAttr { private includeParty: boolean; @@ -7210,8 +7121,6 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { /** * Attribute used to copy a previously-used move. * Used for {@linkcode MoveId.COPYCAT} and {@linkcode MoveId.MIRROR_MOVE} - * @see {@linkcode apply} for move selection and move call - * @extends CallMoveAttr to call a selected move */ export class CopyMoveAttr extends CallMoveAttr { private mirrorMove: boolean; @@ -7488,11 +7397,11 @@ export class SketchAttr extends MoveEffectAttr { } /** * User copies the opponent's last used move, if possible - * @param {Pokemon} user Pokemon that used the move and will replace Sketch with the copied move - * @param {Pokemon} target Pokemon that the user wants to copy a move from - * @param {Move} move Move being used - * @param {any[]} args Unused - * @returns {boolean} true if the function succeeds, otherwise false + * @param user Pokemon that used the move and will replace Sketch with the copied move + * @param target Pokemon that the user wants to copy a move from + * @param move Move being used + * @param args Unused + * @returns true if the function succeeds, otherwise false */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -7655,10 +7564,6 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr { /** * Attribute used for moves that suppress abilities like {@linkcode MoveId.GASTRO_ACID}. * A suppressed ability cannot be activated. - * - * @extends MoveEffectAttr - * @see {@linkcode apply} - * @see {@linkcode getCondition} */ export class SuppressAbilitiesAttr extends MoveEffectAttr { /** Sets ability suppression for the target pokemon and displays a message. */ @@ -7684,8 +7589,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr { /** * Applies the effects of {@linkcode SuppressAbilitiesAttr} if the target has already moved this turn. - * @extends MoveEffectAttr - * @see {@linkcode MoveId.CORE_ENFORCER} (the move which uses this effect) + * @see {@linkcode MoveId.CORE_ENFORCER} */ export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr { /** @@ -7734,8 +7638,6 @@ export class TransformAttr extends MoveEffectAttr { /** * Attribute used for status moves, namely Speed Swap, * that swaps the user's and target's corresponding stats. - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class SwapStatAttr extends MoveEffectAttr { /** The stat to be swapped between the user and the target */ @@ -7776,7 +7678,6 @@ export class SwapStatAttr extends MoveEffectAttr { /** * Attribute used to switch the user's own stats. * Used by Power Shift. - * @extends MoveEffectAttr */ export class ShiftStatAttr extends MoveEffectAttr { private statToSwitch: EffectiveStat; @@ -7791,7 +7692,7 @@ export class ShiftStatAttr extends MoveEffectAttr { /** * Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes. - * @param {Pokemon} user the {@linkcode Pokemon} that used the move + * @param user the {@linkcode Pokemon} that used the move * @param target n/a * @param move n/a * @param args n/a @@ -7819,7 +7720,7 @@ export class ShiftStatAttr extends MoveEffectAttr { /** * Encourages the user to use the move if the stat to switch with is greater than the stat to switch. - * @param {Pokemon} user the {@linkcode Pokemon} that used the move + * @param user the {@linkcode Pokemon} that used the move * @param target n/a * @param move n/a * @returns number of points to add to the user's benefit score @@ -7833,8 +7734,6 @@ export class ShiftStatAttr extends MoveEffectAttr { * Attribute used for status moves, namely Power Split and Guard Split, * that take the average of a user's and target's corresponding * stats and assign that average back to each corresponding stat. - * @extends MoveEffectAttr - * @see {@linkcode apply} */ export class AverageStatsAttr extends MoveEffectAttr { /** The stats to be averaged individually between the user and the target */ @@ -7887,11 +7786,7 @@ export class MoneyAttr extends MoveEffectAttr { } } -/** - * Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user. - * - * @extends MoveEffectAttr - */ +/** Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user */ export class DestinyBondAttr extends MoveEffectAttr { constructor() { super(true, { trigger: MoveEffectTrigger.PRE_APPLY }); @@ -7902,7 +7797,7 @@ export class DestinyBondAttr extends MoveEffectAttr { * @param user {@linkcode Pokemon} that is having the tag applied to. * @param target {@linkcode Pokemon} N/A * @param move {@linkcode Move} {@linkcode Move.DESTINY_BOND} - * @param {any[]} args N/A + * @param args N/A * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -7912,10 +7807,7 @@ export class DestinyBondAttr extends MoveEffectAttr { } } -/** - * Attribute to apply a battler tag to the target if they have had their stats boosted this turn. - * @extends AddBattlerTagAttr - */ +/** Attribute to apply a battler tag to the target if they have had their stats boosted this turn */ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr { constructor(tag: BattlerTagType) { super(tag, false, false, 2, 5); @@ -7925,7 +7817,7 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr { * @param user {@linkcode Pokemon} using this move * @param target {@linkcode Pokemon} target of this move * @param move {@linkcode Move} being used - * @param {any[]} args N/A + * @param args N/A * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -7938,7 +7830,6 @@ export class AddBattlerTagIfBoostedAttr extends AddBattlerTagAttr { /** * Attribute to apply a status effect to the target if they have had their stats boosted this turn. - * @extends MoveEffectAttr */ export class StatusIfBoostedAttr extends MoveEffectAttr { public effect: StatusEffect; @@ -7952,7 +7843,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr { * @param user {@linkcode Pokemon} using this move * @param target {@linkcode Pokemon} target of this move * @param move {@linkcode Move} N/A - * @param {any[]} args N/A + * @param args N/A * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -8034,7 +7925,6 @@ export class AfterYouAttr extends MoveEffectAttr { /** * Move effect to force the target to move last, ignoring priority. * If applied to multiple targets, they move in speed order after all other moves. - * @extends MoveEffectAttr */ export class ForceLastAttr extends MoveEffectAttr { /** @@ -8213,11 +8103,11 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { /** * User changes its type to a random type that resists the target's last used move - * @param {Pokemon} user Pokemon that used the move and will change types - * @param {Pokemon} target Opposing pokemon that recently used a move - * @param {Move} move Move being used - * @param {any[]} args Unused - * @returns {boolean} true if the function succeeds + * @param user Pokemon that used the move and will change types + * @param target Opposing pokemon that recently used a move + * @param move Move being used + * @param args Unused + * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!super.apply(user, target, move, args)) { @@ -8278,9 +8168,6 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { * Drops the target's immunity to types it is immune to * and makes its evasiveness be ignored during accuracy * checks. Used by: {@linkcode MoveId.ODOR_SLEUTH | Odor Sleuth}, {@linkcode MoveId.MIRACLE_EYE | Miracle Eye} and {@linkcode MoveId.FORESIGHT | Foresight} - * - * @extends AddBattlerTagAttr - * @see {@linkcode apply} */ export class ExposedMoveAttr extends AddBattlerTagAttr { constructor(tagType: BattlerTagType) { diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 5462c0eb336..cb34190a584 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -46,8 +46,8 @@ import { } from "#mystery-encounters/mystery-encounter-requirements"; import { getRandomPartyMemberFunc, trainerConfigs } from "#trainers/trainer-config"; import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#utils/common"; import i18next from "i18next"; diff --git a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts index 42907455e22..24ea7167864 100644 --- a/src/data/mystery-encounters/encounters/clowning-around-encounter.ts +++ b/src/data/mystery-encounters/encounters/clowning-around-encounter.ts @@ -45,7 +45,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option"; import { trainerConfigs } from "#trainers/trainer-config"; import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template"; -import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler"; import { randSeedInt, randSeedShuffle } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import i18next from "i18next"; diff --git a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts index 598f9d496a2..33512ff0760 100644 --- a/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts +++ b/src/data/mystery-encounters/encounters/dancing-lessons-encounter.ts @@ -37,7 +37,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou import { MoveRequirement } from "#mystery-encounters/mystery-encounter-requirements"; import { DANCING_MOVES } from "#mystery-encounters/requirement-groups"; import { PokemonData } from "#system/pokemon-data"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import i18next from "i18next"; diff --git a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts index 79cccd91b26..8cd4c8bee66 100644 --- a/src/data/mystery-encounters/encounters/delibirdy-encounter.ts +++ b/src/data/mystery-encounters/encounters/delibirdy-encounter.ts @@ -33,7 +33,7 @@ import { MoneyRequirement, } from "#mystery-encounters/mystery-encounter-requirements"; import i18next from "#plugins/i18n"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import { randSeedItem } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; diff --git a/src/data/mystery-encounters/encounters/field-trip-encounter.ts b/src/data/mystery-encounters/encounters/field-trip-encounter.ts index 30c4026fcad..81d9bce3a76 100644 --- a/src/data/mystery-encounters/encounters/field-trip-encounter.ts +++ b/src/data/mystery-encounters/encounters/field-trip-encounter.ts @@ -18,7 +18,7 @@ import { import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import i18next from "i18next"; /** i18n namespace for the encounter */ diff --git a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts index 7dbbe24fb69..823f016029e 100644 --- a/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts +++ b/src/data/mystery-encounters/encounters/global-trade-system-encounter.ts @@ -42,7 +42,7 @@ import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encou import { PartySizeRequirement } from "#mystery-encounters/mystery-encounter-requirements"; import { PokemonData } from "#system/pokemon-data"; import { MusicPreference } from "#system/settings"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import { isNullOrUndefined, NumberHolder, randInt, randSeedInt, randSeedItem, randSeedShuffle } from "#utils/common"; import { getEnumKeys } from "#utils/enums"; import { getRandomLocaleEntry } from "#utils/i18n"; diff --git a/src/data/mystery-encounters/encounters/training-session-encounter.ts b/src/data/mystery-encounters/encounters/training-session-encounter.ts index 796840c431f..033a54cc5f5 100644 --- a/src/data/mystery-encounters/encounters/training-session-encounter.ts +++ b/src/data/mystery-encounters/encounters/training-session-encounter.ts @@ -27,7 +27,7 @@ import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#mystery-encounters/mystery-encounter-option"; import { PokemonData } from "#system/pokemon-data"; import type { HeldModifierConfig } from "#types/held-modifier-config"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import { isNullOrUndefined, randSeedShuffle } from "#utils/common"; import { getEnumValues } from "#utils/enums"; import i18next from "i18next"; diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index ea621238121..273e14248e6 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -576,10 +576,9 @@ export class MysteryEncounterBuilder implements Partial { */ /** - * @static Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType - * NOTE: if new functions are added to {@linkcode MysteryEncounter} class + * Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType * @param encounterType - * @returns this + * @returns a new instance of MysteryEncounterBuilder with encounterType set */ static withEncounterType( encounterType: MysteryEncounterType, diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index fdc92994e66..aa569f11aca 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -46,9 +46,9 @@ import type { PokemonData } from "#system/pokemon-data"; import type { TrainerConfig } from "#trainers/trainer-config"; import { trainerConfigs } from "#trainers/trainer-config"; import type { HeldModifierConfig } from "#types/held-modifier-config"; -import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { PartyOption, PokemonSelectFilter } from "#ui/handlers/party-ui-handler"; -import { PartyUiMode } from "#ui/handlers/party-ui-handler"; +import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import type { PartyOption, PokemonSelectFilter } from "#ui/party-ui-handler"; +import { PartyUiMode } from "#ui/party-ui-handler"; import { coerceArray, isNullOrUndefined, randomString, randSeedInt, randSeedItem } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import i18next from "i18next"; @@ -969,7 +969,7 @@ export function handleMysteryEncounterBattleStartEffects() { /** * Can queue extra phases or logic during {@linkcode TurnInitPhase} * Should mostly just be used for injecting custom phases into the battle system on turn start - * @return boolean - if true, will skip the remainder of the {@linkcode TurnInitPhase} + * @returns boolean - if true, will skip the remainder of the {@linkcode TurnInitPhase} */ export function handleMysteryEncounterTurnStartEffects(): boolean { const encounter = globalScene.currentBattle.mysteryEncounter; @@ -986,7 +986,7 @@ export function handleMysteryEncounterTurnStartEffects(): boolean { * @param level the level of the mon, which differs between MEs * @param isBoss whether the mon should be a Boss * @param rerollHidden whether the mon should get an extra roll for Hidden Ability - * @returns {@linkcode EnemyPokemon} for the requested encounter + * @returns for the requested encounter */ export function getRandomEncounterSpecies(level: number, isBoss = false, rerollHidden = false): EnemyPokemon { let bossSpecies: PokemonSpecies; diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index 0d07300d00d..8f6c78fab9c 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -31,9 +31,9 @@ import { showEncounterText, } from "#mystery-encounters/encounter-dialogue-utils"; import { achvs } from "#system/achv"; -import type { PartyOption } from "#ui/handlers/party-ui-handler"; -import { PartyUiMode } from "#ui/handlers/party-ui-handler"; -import { SummaryUiMode } from "#ui/handlers/summary-ui-handler"; +import type { PartyOption } from "#ui/party-ui-handler"; +import { PartyUiMode } from "#ui/party-ui-handler"; +import { SummaryUiMode } from "#ui/summary-ui-handler"; import { applyChallenges } from "#utils/challenge-utils"; import { BooleanHolder, isNullOrUndefined, randSeedInt } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; diff --git a/src/data/pokemon-forms/form-change-triggers.ts b/src/data/pokemon-forms/form-change-triggers.ts index 9da3538741c..f51b090878f 100644 --- a/src/data/pokemon-forms/form-change-triggers.ts +++ b/src/data/pokemon-forms/form-change-triggers.ts @@ -289,7 +289,7 @@ export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChange /** * Checks if the Pokemon has the required ability and the weather is one that will revert * the Pokemon to its original form or the weather or ability is suppressed - * @param {Pokemon} pokemon the pokemon that is trying to do the form change + * @param pokemon the pokemon that is trying to do the form change * @returns `true` if the Pokemon will revert to its original form, `false` otherwise */ canChange(pokemon: Pokemon): boolean { diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index f91d3aaf1f2..2d76c2c0400 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -26,8 +26,8 @@ import { loadPokemonVariantAssets } from "#sprites/pokemon-sprite"; import { hasExpSprite } from "#sprites/sprite-utils"; import type { Variant, VariantSet } from "#sprites/variant"; import { populateVariantColorCache, variantColorCache, variantData } from "#sprites/variant"; -import type { StarterMoveset } from "#system/game-data"; import type { Localizable } from "#types/locales"; +import type { StarterMoveset } from "#types/save-data"; import { isNullOrUndefined, randSeedFloat, randSeedGauss, randSeedInt } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import { toCamelCase, toPascalCase } from "#utils/strings"; @@ -919,7 +919,7 @@ export class PokemonSpecies extends PokemonSpeciesForm implements Localizable { * The calculation with evolution delay is a weighted average of the easeIn and easeOut functions where preferredMinLevel is the denominator. * This also means a lower value of x will lead to a higher evolution chance. * @param strength {@linkcode PartyMemberStrength} The strength of the party member in question - * @returns {@linkcode number} The level difference from expected evolution level tolerated for a mon to be unevolved. Lower value = higher evolution chance. + * @returns The level difference from expected evolution level tolerated for a mon to be unevolved. Lower value = higher evolution chance. */ private getStrengthLevelDiff(strength: PartyMemberStrength): number { switch (Math.min(strength, PartyMemberStrength.STRONGER)) { diff --git a/src/data/splash-messages.ts b/src/data/splash-messages.ts index 21e7e5d05e6..a7791af78ac 100644 --- a/src/data/splash-messages.ts +++ b/src/data/splash-messages.ts @@ -234,7 +234,7 @@ const seasonalSplashMessages: Season[] = [ "valentines.happyValentines", "valentines.fullOfLove", "valentines.applinForYou", - "valentines.thePowerOfLoveIsThreeThirtyBST", + "valentines.thePowerOfLoveIsThreeThirtyBst", "valentines.haveAHeartScale", "valentines.i<3You", ], @@ -265,7 +265,7 @@ const seasonalSplashMessages: Season[] = [ "aprilFools.whoIsFinn", "aprilFools.watchOutForShadowPokemon", "aprilFools.nowWithDarkTypeLuxray", - "aprilFools.onlyOnPokerogueNetAGAIN", + "aprilFools.onlyOnPokerogueNetAgain", "aprilFools.noFreeVouchers", "aprilFools.altffourAchievementPoints", "aprilFools.rokePogue", diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index 2870fd7f808..9d891444829 100644 --- a/src/data/trainers/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -204,7 +204,7 @@ export class TrainerConfig { /** * Returns the derived trainer type for a given trainer type. * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) - * @returns {TrainerType} - The derived trainer type. + * @returns - The derived trainer type. */ getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType { let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType; @@ -274,9 +274,9 @@ export class TrainerConfig { /** * Sets the configuration for trainers with genders, including the female name and encounter background music (BGM). - * @param {string} [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned. - * @param {TrainerType | string} [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @param [nameFemale] The name of the female trainer. If 'Ivy', a localized name will be assigned. + * @param [femaleEncounterBgm] The encounter BGM for the female trainer, which can be a TrainerType or a string. + * @returns The updated TrainerConfig instance. */ setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig { // If the female name is 'Ivy' (the rival), assign a localized name. @@ -314,7 +314,7 @@ export class TrainerConfig { * Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM. * @param nameDouble The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles). * @param doubleEncounterBgm The encounter BGM for the double trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig { this.hasDouble = true; @@ -331,7 +331,7 @@ export class TrainerConfig { /** * Sets the trainer type for double battles. * @param trainerTypeDouble The TrainerType of the partner in a double battle. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig { this.trainerTypeDouble = trainerTypeDouble; @@ -356,7 +356,7 @@ export class TrainerConfig { /** * Sets the title for double trainers * @param titleDouble The key for the title in the i18n file. (e.g., "champion_double"). - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ setDoubleTitle(titleDouble: string): TrainerConfig { // First check if i18n is initialized @@ -523,9 +523,9 @@ export class TrainerConfig { * Initializes the trainer configuration for an evil team admin. * @param title The title of the evil team admin. * @param poolName The evil team the admin belongs to. - * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader. + * @param signatureSpecies The signature species for the evil team leader. * @param specialtyType The specialty Type of the admin, if they have one - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ initForEvilTeamAdmin( title: string, @@ -566,7 +566,7 @@ export class TrainerConfig { /** * Initializes the trainer configuration for a Stat Trainer, as part of the Trainer's Test Mystery Encounter. * @param _isMale Whether the stat trainer is Male or Female (for localization of the title). - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ initForStatTrainer(_isMale = false): TrainerConfig { if (!getIsInitialized()) { @@ -590,10 +590,10 @@ export class TrainerConfig { /** * Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though. - * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the evil team leader. - * @param {PokemonType} specialtyType The specialty type for the evil team Leader. + * @param signatureSpecies The signature species for the evil team leader. + * @param specialtyType The specialty type for the evil team Leader. * @param boolean Whether or not this is the rematch fight - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ initForEvilTeamLeader( title: string, @@ -631,12 +631,12 @@ export class TrainerConfig { /** * Initializes the trainer configuration for a Gym Leader. - * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Gym Leader. Added to party in reverse order. + * @param signatureSpecies The signature species for the Gym Leader. Added to party in reverse order. * @param isMale Whether the Gym Leader is Male or Not (for localization of the title). - * @param {PokemonType} specialtyType The specialty type for the Gym Leader. + * @param specialtyType The specialty type for the Gym Leader. * @param ignoreMinTeraWave Whether the Gym Leader always uses Tera (true), or only Teras after {@linkcode GYM_LEADER_TERA_WAVE} (false). Defaults to false. * @param teraSlot Optional, sets the party member in this slot to Terastallize. Wraps based on party size. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ initForGymLeader( signatureSpecies: (SpeciesId | SpeciesId[])[], @@ -748,9 +748,9 @@ export class TrainerConfig { /** * Initializes the trainer configuration for a Champion. - * @param {SpeciesId | SpeciesId[]} signatureSpecies The signature species for the Champion. + * @param signatureSpecies The signature species for the Champion. * @param isMale Whether the Champion is Male or Female (for localization of the title). - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ initForChampion(isMale: boolean): TrainerConfig { // Check if the internationalization (i18n) system is initialized. @@ -785,7 +785,7 @@ export class TrainerConfig { /** * Sets a localized name for the trainer. This should only be used for trainers that dont use a "initFor" function and are considered "named" trainers * @param name - The name of the trainer. - * @returns {TrainerConfig} The updated TrainerConfig instance. + * @returns The updated TrainerConfig instance. */ setLocalizedName(name: string): TrainerConfig { // Check if the internationalization (i18n) system is initialized. @@ -798,9 +798,9 @@ export class TrainerConfig { /** * Retrieves the title for the trainer based on the provided trainer slot and variant. - * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. - * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. - * @returns {string} - The title of the trainer. + * @param trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. + * @param variant - The variant of the trainer to determine the specific title. + * @returns - The title of the trainer. */ getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string { const ret = this.name; diff --git a/src/enums/move-flags.ts b/src/enums/move-flags.ts index e639a1eb190..acd73f897e7 100644 --- a/src/enums/move-flags.ts +++ b/src/enums/move-flags.ts @@ -29,7 +29,7 @@ export enum MoveFlags { SLICING_MOVE = 1 << 8, /** * Indicates a move should be affected by {@linkcode AbilityId.RECKLESS} - * @see {@linkcode Move.recklessMove()} + * @see {@linkcode Move.recklessMove} */ RECKLESS_MOVE = 1 << 9, /** Indicates a move should be affected by {@linkcode AbilityId.BULLETPROOF} */ diff --git a/src/events/arena.ts b/src/events/arena.ts index 5415b8eb026..cf287de3176 100644 --- a/src/events/arena.ts +++ b/src/events/arena.ts @@ -16,10 +16,7 @@ export enum ArenaEventType { TAG_REMOVED = "onTagRemoved", } -/** - * Base container class for all {@linkcode ArenaEventType} events - * @extends Event - */ +/** Base container class for all {@linkcode ArenaEventType} events */ export class ArenaEvent extends Event { /** The total duration of the {@linkcode ArenaEventType} */ public duration: number; @@ -29,10 +26,7 @@ export class ArenaEvent extends Event { this.duration = duration; } } -/** - * Container class for {@linkcode ArenaEventType.WEATHER_CHANGED} events - * @extends ArenaEvent - */ +/** Container class for {@linkcode ArenaEventType.WEATHER_CHANGED} events */ export class WeatherChangedEvent extends ArenaEvent { /** The {@linkcode WeatherType} being overridden */ public oldWeatherType: WeatherType; @@ -45,10 +39,7 @@ export class WeatherChangedEvent extends ArenaEvent { this.newWeatherType = newWeatherType; } } -/** - * Container class for {@linkcode ArenaEventType.TERRAIN_CHANGED} events - * @extends ArenaEvent - */ +/** Container class for {@linkcode ArenaEventType.TERRAIN_CHANGED} events */ export class TerrainChangedEvent extends ArenaEvent { /** The {@linkcode TerrainType} being overridden */ public oldTerrainType: TerrainType; @@ -62,10 +53,7 @@ export class TerrainChangedEvent extends ArenaEvent { } } -/** - * Container class for {@linkcode ArenaEventType.TAG_ADDED} events - * @extends ArenaEvent - */ +/** Container class for {@linkcode ArenaEventType.TAG_ADDED} events */ export class TagAddedEvent extends ArenaEvent { /** The {@linkcode ArenaTagType} being added */ public arenaTagType: ArenaTagType; @@ -91,10 +79,7 @@ export class TagAddedEvent extends ArenaEvent { this.arenaTagMaxLayers = arenaTagMaxLayers!; // TODO: is this bang correct? } } -/** - * Container class for {@linkcode ArenaEventType.TAG_REMOVED} events - * @extends ArenaEvent - */ +/** Container class for {@linkcode ArenaEventType.TAG_REMOVED} events */ export class TagRemovedEvent extends ArenaEvent { /** The {@linkcode ArenaTagType} being removed */ public arenaTagType: ArenaTagType; diff --git a/src/events/battle-scene.ts b/src/events/battle-scene.ts index 29aee1053cd..fdee812f54e 100644 --- a/src/events/battle-scene.ts +++ b/src/events/battle-scene.ts @@ -43,10 +43,7 @@ export enum BattleSceneEventType { NEW_ARENA = "onNewArena", } -/** - * Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events */ export class CandyUpgradeNotificationChangedEvent extends Event { /** The new value the setting was changed to */ public newValue: number; @@ -57,10 +54,7 @@ export class CandyUpgradeNotificationChangedEvent extends Event { } } -/** - * Container class for {@linkcode BattleSceneEventType.MOVE_USED} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.MOVE_USED} events */ export class MoveUsedEvent extends Event { /** The ID of the {@linkcode Pokemon} that used the {@linkcode Move} */ public pokemonId: number; @@ -76,10 +70,7 @@ export class MoveUsedEvent extends Event { this.ppUsed = ppUsed; } } -/** - * Container class for {@linkcode BattleSceneEventType.BERRY_USED} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.BERRY_USED} events */ export class BerryUsedEvent extends Event { /** The {@linkcode BerryModifier} being used */ public berryModifier: BerryModifier; @@ -90,28 +81,19 @@ export class BerryUsedEvent extends Event { } } -/** - * Container class for {@linkcode BattleSceneEventType.ENCOUNTER_PHASE} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.ENCOUNTER_PHASE} events */ export class EncounterPhaseEvent extends Event { constructor() { super(BattleSceneEventType.ENCOUNTER_PHASE); } } -/** - * Container class for {@linkcode BattleSceneEventType.TURN_INIT} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.TURN_INIT} events */ export class TurnInitEvent extends Event { constructor() { super(BattleSceneEventType.TURN_INIT); } } -/** - * Container class for {@linkcode BattleSceneEventType.TURN_END} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.TURN_END} events */ export class TurnEndEvent extends Event { /** The amount of turns in the current battle */ public turnCount: number; @@ -121,10 +103,7 @@ export class TurnEndEvent extends Event { this.turnCount = turnCount; } } -/** - * Container class for {@linkcode BattleSceneEventType.NEW_ARENA} events - * @extends Event - */ +/** Container class for {@linkcode BattleSceneEventType.NEW_ARENA} events */ export class NewArenaEvent extends Event { constructor() { super(BattleSceneEventType.NEW_ARENA); diff --git a/src/events/egg.ts b/src/events/egg.ts index a0c26c82883..30a005d192f 100644 --- a/src/events/egg.ts +++ b/src/events/egg.ts @@ -8,7 +8,6 @@ export enum EggEventType { /** * Container class for {@linkcode EggEventType.EGG_COUNT_CHANGED} events - * @extends Event */ export class EggCountChangedEvent extends Event { /** The updated egg count. */ diff --git a/src/field/arena.ts b/src/field/arena.ts index ed23e42b119..ff7379b2a4a 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -732,14 +732,12 @@ export class Arena { * Attempt to get a tag from the Arena via {@linkcode getTagOnSide} that applies to both sides * @param tagType - The {@linkcode ArenaTagType} to retrieve * @returns The existing {@linkcode ArenaTag}, or `undefined` if not present. - * @overload */ getTag(tagType: ArenaTagType): ArenaTag | undefined; /** * Attempt to get a tag from the Arena via {@linkcode getTagOnSide} that applies to both sides * @param tagType - The constructor of the {@linkcode ArenaTag} to retrieve * @returns The existing {@linkcode ArenaTag}, or `undefined` if not present. - * @overload */ getTag(tagType: Constructor | AbstractConstructor): T | undefined; getTag(tagType: ArenaTagType | Constructor | AbstractConstructor): ArenaTag | undefined { diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 0b5c825acde..8b542e409e7 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -137,18 +137,18 @@ import { loadMoveAnimations } from "#sprites/pokemon-asset-loader"; import type { Variant } from "#sprites/variant"; import { populateVariantColors, variantColorCache, variantData } from "#sprites/variant"; import { achvs } from "#system/achv"; -import type { StarterDataEntry, StarterMoveset } from "#system/game-data"; import type { PokemonData } from "#system/pokemon-data"; import { RibbonData } from "#system/ribbons/ribbon-data"; import { awardRibbonsToSpeciesLine } from "#system/ribbons/ribbon-methods"; import type { AbAttrMap, AbAttrString, TypeMultiplierAbAttrParams } from "#types/ability-types"; import type { DamageCalculationResult, DamageResult } from "#types/damage-result"; import type { IllusionData } from "#types/illusion-data"; +import type { StarterDataEntry, StarterMoveset } from "#types/save-data"; import type { TurnMove } from "#types/turn-move"; import { BattleInfo } from "#ui/battle-info"; import { EnemyBattleInfo } from "#ui/enemy-battle-info"; -import type { PartyOption } from "#ui/handlers/party-ui-handler"; -import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import type { PartyOption } from "#ui/party-ui-handler"; +import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import { PlayerBattleInfo } from "#ui/player-battle-info"; import { applyChallenges } from "#utils/challenge-utils"; import { @@ -2647,11 +2647,11 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { /** * Gets all level up moves in a given range for a particular pokemon. - * @param {number} startingLevel Don't include moves below this level - * @param {boolean} includeEvolutionMoves Whether to include evolution moves - * @param {boolean} simulateEvolutionChain Whether to include moves from prior evolutions - * @param {boolean} includeRelearnerMoves Whether to include moves that would require a relearner. Note the move relearner inherently allows evolution moves - * @returns {LevelMoves} A list of moves and the levels they can be learned at + * @param startingLevel Don't include moves below this level + * @param includeEvolutionMoves Whether to include evolution moves + * @param simulateEvolutionChain Whether to include moves from prior evolutions + * @param includeRelearnerMoves Whether to include moves that would require a relearner. Note the move relearner inherently allows evolution moves + * @returns A list of moves and the levels they can be learned at */ getLevelMoves( startingLevel?: number, @@ -3209,9 +3209,55 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { Math.ceil(Math.pow(m[1], weightMultiplier) * 100), ]); + const STAB_BLACKLIST: ReadonlySet = new Set([ + MoveId.BEAT_UP, + MoveId.BELCH, + MoveId.BIDE, + MoveId.COMEUPPANCE, + MoveId.COUNTER, + MoveId.DOOM_DESIRE, + MoveId.DRAGON_RAGE, + MoveId.DREAM_EATER, + MoveId.ENDEAVOR, + MoveId.EXPLOSION, + MoveId.FAKE_OUT, + MoveId.FIRST_IMPRESSION, + MoveId.FISSURE, + MoveId.FLING, + MoveId.FOCUS_PUNCH, + MoveId.FUTURE_SIGHT, + MoveId.GUILLOTINE, + MoveId.HOLD_BACK, + MoveId.HORN_DRILL, + MoveId.LAST_RESORT, + MoveId.METAL_BURST, + MoveId.MIRROR_COAT, + MoveId.MISTY_EXPLOSION, + MoveId.NATURAL_GIFT, + MoveId.NATURES_MADNESS, + MoveId.NIGHT_SHADE, + MoveId.PSYWAVE, + MoveId.RUINATION, + MoveId.SELF_DESTRUCT, + MoveId.SHEER_COLD, + MoveId.SHELL_TRAP, + MoveId.SKY_DROP, + MoveId.SNORE, + MoveId.SONIC_BOOM, + MoveId.SPIT_UP, + MoveId.STEEL_BEAM, + MoveId.STEEL_ROLLER, + MoveId.SUPER_FANG, + MoveId.SYNCHRONOISE, + MoveId.UPPER_HAND, + ]); + // All Pokemon force a STAB move first const stabMovePool = baseWeights.filter( - m => allMoves[m[0]].category !== MoveCategory.STATUS && this.isOfType(allMoves[m[0]].type), + m => + allMoves[m[0]].category !== MoveCategory.STATUS + && this.isOfType(allMoves[m[0]].type) + && !STAB_BLACKLIST.has(m[0]), ); if (stabMovePool.length > 0) { @@ -3224,7 +3270,9 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { this.moveset.push(new PokemonMove(stabMovePool[index][0])); } else { // If there are no damaging STAB moves, just force a random damaging move - const attackMovePool = baseWeights.filter(m => allMoves[m[0]].category !== MoveCategory.STATUS); + const attackMovePool = baseWeights.filter( + m => allMoves[m[0]].category !== MoveCategory.STATUS && !STAB_BLACKLIST.has(m[0]), + ); if (attackMovePool.length > 0) { const totalWeight = attackMovePool.reduce((v, m) => v + m[1], 0); let rand = randSeedInt(totalWeight); @@ -3261,7 +3309,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { } else if (allMoves[m[0]].category !== MoveCategory.STATUS) { ret = Math.ceil( (m[1] / Math.max(Math.pow(4, this.moveset.filter(mo => (mo.getMove().power ?? 0) > 1).length) / 8, 0.5)) - * (this.isOfType(allMoves[m[0]].type) ? 20 : 1), + * (this.isOfType(allMoves[m[0]].type) && !STAB_BLACKLIST.has(m[0]) ? 20 : 1), ); } else { ret = m[1]; @@ -3448,7 +3496,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * @param isCritical determines whether a critical hit has occurred or not (`false` by default) * @param simulated determines whether effects are applied without altering game state (`true` by default) * @param ignoreHeldItems determines whether this Pokemon's held items should be ignored during the stat calculation, default `false` - * @return the stat stage multiplier to be used for effective stat calculation + * @returns the stat stage multiplier to be used for effective stat calculation */ getStatStageMultiplier( stat: EffectiveStat, @@ -3504,8 +3552,8 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * This method considers various factors such as the user's accuracy level, the target's evasion level, * abilities, and modifiers to compute the final accuracy multiplier. * - * @param target {@linkcode Pokemon} - The target Pokémon against which the move is used. - * @param sourceMove {@linkcode Move} - The move being used by the user. + * @param target - The target Pokémon against which the move is used. + * @param sourceMove - The move being used by the user. * @returns The calculated accuracy multiplier. */ getAccuracyMultiplier(target: Pokemon, sourceMove: Move): number { @@ -4020,7 +4068,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { */ getCriticalHitResult(source: Pokemon, move: Move): boolean { if (move.hasAttr("FixedDamageAttr")) { - // fixed damage moves (Dragon Rage, etc.) will nevet crit + // fixed damage moves (Dragon Rage, etc.) will never crit return false; } @@ -4244,18 +4292,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { return false; } - /**@overload */ getTag(tagType: BattlerTagType.GRUDGE): GrudgeTag | undefined; - - /** @overload */ getTag(tagType: BattlerTagType.SUBSTITUTE): SubstituteTag | undefined; - - /** @overload */ getTag(tagType: BattlerTagType): BattlerTag | undefined; - - /** @overload */ getTag(tagType: Constructor): T | undefined; - getTag(tagType: BattlerTagType | Constructor): BattlerTag | undefined { return typeof tagType === "function" ? this.summonData.tags.find(t => t instanceof tagType) @@ -4403,7 +4443,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { * @param user - The move user * @param target - The target of the move * - * @returns {boolean} `true` if the move is disabled for this Pokemon due to the player's target selection + * @returns `true` if the move is disabled for this Pokemon due to the player's target selection * * @see {@linkcode MoveRestrictionBattlerTag} */ @@ -5195,7 +5235,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { /** * Reset a {@linkcode Pokemon}'s {@linkcode PokemonWaveData | waveData}. * Should be called upon starting a new wave in addition to whenever an arena transition occurs. - * @see {@linkcode resetBattleAndWaveData()} + * @see {@linkcode resetBattleAndWaveData} */ resetWaveData(): void { this.waveData = new PokemonWaveData(); @@ -5630,7 +5670,6 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { /** * Generates a random number using the current battle's seed, or the global seed if `globalScene.currentBattle` is falsy - * * This calls either {@linkcode BattleScene.randBattleSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle-scene.ts` * which calls {@linkcode Battle.randSeedInt}({@linkcode range}, {@linkcode min}) in `src/battle.ts` * which calls {@linkcode randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`, diff --git a/src/game-mode.ts b/src/game-mode.ts index 05850dec9ee..9ea3adf59d3 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -315,8 +315,8 @@ export class GameMode implements GameModeConfig { /** * Checks whether there is a fixed battle on this gamemode on a given wave. - * @param {number} waveIndex The wave to check. - * @returns {boolean} If this game mode has a fixed battle on this wave + * @param waveIndex The wave to check. + * @returns If this game mode has a fixed battle on this wave */ isFixedBattle(waveIndex: number): boolean { const dummyConfig = new FixedBattleConfig(); @@ -328,8 +328,8 @@ export class GameMode implements GameModeConfig { /** * Returns the config for the fixed battle for a particular wave. - * @param {number} waveIndex The wave to check. - * @returns {boolean} The fixed battle for this wave. + * @param waveIndex The wave to check. + * @returns The fixed battle for this wave. */ getFixedBattle(waveIndex: number): FixedBattleConfig { const challengeConfig = new FixedBattleConfig(); diff --git a/src/init/init.ts b/src/init/init.ts index b717664b654..8452278b3f1 100644 --- a/src/init/init.ts +++ b/src/init/init.ts @@ -11,7 +11,7 @@ import { initMoves } from "#moves/move"; import { initMysteryEncounters } from "#mystery-encounters/mystery-encounters"; import { initAchievements } from "#system/achv"; import { initVouchers } from "#system/voucher"; -import { initStatsKeys } from "#ui/handlers/game-stats-ui-handler"; +import { initStatsKeys } from "#ui/game-stats-ui-handler"; /** Initialize the game. */ export function initializeGame() { diff --git a/src/loading-scene.ts b/src/loading-scene.ts index c01c5287dc5..a4cbaf9ae64 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -154,6 +154,7 @@ export class LoadingScene extends SceneBase { this.loadImage("select_gen_cursor", "ui"); this.loadImage("select_gen_cursor_highlight", "ui"); + this.loadImage("language_icon", "ui"); this.loadImage("saving_icon", "ui"); this.loadImage("discord", "ui"); this.loadImage("google", "ui"); diff --git a/src/messages.ts b/src/messages.ts index 177b4cc9b05..c9673345110 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -6,8 +6,8 @@ import i18next from "i18next"; /** * Retrieves the Pokemon's name, potentially with an affix indicating its role (wild or foe) in the current battle context, translated * @param pokemon {@linkcode Pokemon} name and battle context will be retrieved from this instance - * @param {boolean} useIllusion - Whether we want the name of the illusion or not. Default value : true - * @returns {string} ex: "Wild Gengar", "Ectoplasma sauvage" + * @param useIllusion - Whether we want the name of the illusion or not. Default value : true + * @returns ex: "Wild Gengar", "Ectoplasma sauvage" */ export function getPokemonNameWithAffix(pokemon: Pokemon | undefined, useIllusion = true): string { if (!pokemon) { diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 4b7c40e1a7f..579fb75ce3b 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -115,8 +115,8 @@ import { import type { PokemonMove } from "#moves/pokemon-move"; import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#system/voucher"; import type { ModifierTypeFunc, WeightedModifierTypeWeightFunc } from "#types/modifier-types"; -import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/handlers/party-ui-handler"; -import { PartyUiHandler } from "#ui/handlers/party-ui-handler"; +import type { PokemonMoveSelectFilter, PokemonSelectFilter } from "#ui/party-ui-handler"; +import { PartyUiHandler } from "#ui/party-ui-handler"; import { getModifierTierTextTint } from "#ui/text"; import { applyChallenges } from "#utils/challenge-utils"; import { @@ -150,7 +150,7 @@ export class ModifierType { /** * Checks if the modifier type is of a specific type * @param modifierType - The type to check against - * @return Whether the modifier type is of the specified type + * @returns Whether the modifier type is of the specified type */ public is(modifierType: K): this is ModifierTypeInstanceMap[K] { const targetType = ModifierTypeConstructorMap[modifierType]; @@ -874,11 +874,7 @@ export class AttackTypeBoosterModifierType export type SpeciesStatBoosterItem = keyof typeof SpeciesStatBoosterModifierTypeGenerator.items; -/** - * Modifier type for {@linkcode SpeciesStatBoosterModifier} - * @extends PokemonHeldItemModifierType - * @implements GeneratedPersistentModifierType - */ +/** Modifier type for {@linkcode SpeciesStatBoosterModifier} */ export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType @@ -1396,7 +1392,6 @@ class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator { * Modifier type generator for {@linkcode SpeciesStatBoosterModifierType}, which * encapsulates the logic for weighting the most useful held item from * the current list of {@linkcode items}. - * @extends ModifierTypeGenerator */ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { /** Object comprised of the currently available species-based stat boosting held items */ diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 97291d4ed66..1f470e592c2 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -73,8 +73,8 @@ export class ModifierBar extends Phaser.GameObjects.Container { /** * Method to update content displayed in {@linkcode ModifierBar} - * @param {PersistentModifier[]} modifiers - The list of modifiers to be displayed in the {@linkcode ModifierBar} - * @param {boolean} hideHeldItems - If set to "true", only modifiers not assigned to a Pokémon are displayed + * @param modifiers - The list of modifiers to be displayed in the {@linkcode ModifierBar} + * @param hideHeldItems - If set to "true", only modifiers not assigned to a Pokémon are displayed */ updateModifiers(modifiers: PersistentModifier[], hideHeldItems = false) { this.removeAll(true); @@ -345,9 +345,6 @@ export class AddVoucherModifier extends ConsumableModifier { * modifier will be removed. If a modifier of the same type is to be added, it * will reset {@linkcode battleCount} back to {@linkcode maxBattles} of the * existing modifier instead of adding that modifier directly. - * @extends PersistentModifier - * @abstract - * @see {@linkcode add} */ export abstract class LapsingPersistentModifier extends PersistentModifier { /** The maximum amount of battles the modifier will exist for */ @@ -458,8 +455,6 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { /** * Modifier used for passive items, specifically lures, that * temporarily increases the chance of a double battle. - * @extends LapsingPersistentModifier - * @see {@linkcode apply} */ export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier { public declare type: DoubleBattleChanceBoosterModifierType; @@ -495,8 +490,6 @@ export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier * Modifier used for party-wide items, specifically the X items, that * temporarily increases the stat stage multiplier of the corresponding * {@linkcode TempBattleStat}. - * @extends LapsingPersistentModifier - * @see {@linkcode apply} */ export class TempStatStageBoosterModifier extends LapsingPersistentModifier { /** The stat whose stat stage multiplier will be temporarily increased */ @@ -562,8 +555,6 @@ export class TempStatStageBoosterModifier extends LapsingPersistentModifier { /** * Modifier used for party-wide items, namely Dire Hit, that * temporarily increments the critical-hit stage - * @extends LapsingPersistentModifier - * @see {@linkcode apply} */ export class TempCritBoosterModifier extends LapsingPersistentModifier { clone() { @@ -818,8 +809,6 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi /** * Modifier used for held items, specifically vitamins like Carbos, Hp Up, etc., that * increase the value of a given {@linkcode PermanentStat}. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class BaseStatModifier extends PokemonHeldItemModifier { protected stat: PermanentStat; @@ -1126,8 +1115,6 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { /** * Modifier used for held items that Applies {@linkcode Stat} boost(s) * using a multiplier. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class StatBoosterModifier extends PokemonHeldItemModifier { /** The stats that the held item boosts */ @@ -1194,8 +1181,6 @@ export class StatBoosterModifier extends PokemonHeldItemModifier { /** * Modifier used for held items, specifically Eviolite, that apply * {@linkcode Stat} boost(s) using a multiplier if the holder can evolve. - * @extends StatBoosterModifier - * @see {@linkcode apply} */ export class EvolutionStatBoosterModifier extends StatBoosterModifier { matchType(modifier: Modifier): boolean { @@ -1216,13 +1201,16 @@ export class EvolutionStatBoosterModifier extends StatBoosterModifier { /** * Boosts the incoming stat value by a {@linkcode EvolutionStatBoosterModifier.multiplier} if the holder - * can evolve. Note that, if the holder is a fusion, they will receive + * can evolve + * + * @remarks + * Note that, if the holder is a fusion, they will receive * only half of the boost if either of the fused members are fully * evolved. However, if they are both unevolved, the full boost * will apply. - * @param pokemon {@linkcode Pokemon} that holds the item - * @param _stat {@linkcode Stat} The {@linkcode Stat} to be boosted - * @param statValue{@linkcode NumberHolder} that holds the resulting value of the stat + * @param pokemon - The `Pokemon` holding the item + * @param _stat - The `Stat` to be boosted + * @param statValue - Holds the resulting value of the stat * @returns `true` if the stat boost applies successfully, false otherwise * @see shouldApply */ @@ -1246,8 +1234,6 @@ export class EvolutionStatBoosterModifier extends StatBoosterModifier { /** * Modifier used for held items that Applies {@linkcode Stat} boost(s) using a * multiplier if the holder is of a specific {@linkcode SpeciesId}. - * @extends StatBoosterModifier - * @see {@linkcode apply} */ export class SpeciesStatBoosterModifier extends StatBoosterModifier { /** The species that the held item's stat boost(s) apply to */ @@ -1321,8 +1307,6 @@ export class SpeciesStatBoosterModifier extends StatBoosterModifier { /** * Modifier used for held items that apply critical-hit stage boost(s). - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class CritBoosterModifier extends PokemonHeldItemModifier { /** The amount of stages by which the held item increases the current critical-hit stage value */ @@ -1369,8 +1353,6 @@ export class CritBoosterModifier extends PokemonHeldItemModifier { /** * Modifier used for held items that apply critical-hit stage boost(s) * if the holder is of a specific {@linkcode SpeciesId}. - * @extends CritBoosterModifier - * @see {@linkcode shouldApply} */ export class SpeciesCritBoosterModifier extends CritBoosterModifier { /** The species that the held item's critical-hit stage boost applies to */ @@ -1694,8 +1676,6 @@ export class TurnHealModifier extends PokemonHeldItemModifier { /** * Modifier used for held items, namely Toxic Orb and Flame Orb, that apply a * set {@linkcode StatusEffect} at the end of a turn. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { /** The status effect to be applied by the held item */ @@ -1721,7 +1701,7 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { * would be the only item able to {@linkcode apply} successfully. * @override * @param modifier {@linkcode Modifier} being type tested - * @return `true` if {@linkcode modifier} is an instance of + * @returns `true` if {@linkcode modifier} is an instance of * TurnStatusEffectModifier, false otherwise */ matchType(modifier: Modifier): boolean { @@ -1966,8 +1946,6 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { /** * Modifier used for held items, namely White Herb, that restore adverse stat * stages in battle. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { matchType(modifier: Modifier) { @@ -2013,8 +1991,6 @@ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { /** * Modifier used for held items, namely Mystical Rock, that extend the * duration of weather and terrain effects. - * @extends PokemonHeldItemModifier - * @see {@linkcode apply} */ export class FieldEffectModifier extends PokemonHeldItemModifier { /** @@ -3400,8 +3376,6 @@ export class ExtraModifierModifier extends PersistentModifier { /** * Modifier used for timed boosts to the player's shop item rewards. - * @extends LapsingPersistentModifier - * @see {@linkcode apply} */ export class TempExtraModifierModifier extends LapsingPersistentModifier { /** diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 81f85850e88..2eadae244d5 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -21,9 +21,9 @@ import type { EnemyPokemon } from "#field/pokemon"; import { PokemonHeldItemModifier } from "#modifiers/modifier"; import { PokemonPhase } from "#phases/pokemon-phase"; import { achvs } from "#system/achv"; -import type { PartyOption } from "#ui/handlers/party-ui-handler"; -import { PartyUiMode } from "#ui/handlers/party-ui-handler"; -import { SummaryUiMode } from "#ui/handlers/summary-ui-handler"; +import type { PartyOption } from "#ui/party-ui-handler"; +import { PartyUiMode } from "#ui/party-ui-handler"; +import { SummaryUiMode } from "#ui/summary-ui-handler"; import { applyChallenges } from "#utils/challenge-utils"; import { BooleanHolder } from "#utils/common"; import i18next from "i18next"; diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 4e4747e7c5b..59d02fa31e3 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -215,7 +215,7 @@ export class CommandPhase extends FieldPhase { if (!moveStatus.value) { cannotSelectKey = "battle:moveCannotUseChallenge"; } else if (move.getPpRatio() === 0) { - cannotSelectKey = "battle:moveNoPP"; + cannotSelectKey = "battle:moveNoPp"; } else if (move.getName().endsWith(" (N)")) { cannotSelectKey = "battle:moveNotImplemented"; } else if (user.isMoveRestricted(move.moveId, user)) { diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts index 68c60abc0dc..946288c4fd8 100644 --- a/src/phases/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -9,9 +9,9 @@ import { doShinySparkleAnim } from "#field/anims"; import type { PlayerPokemon } from "#field/pokemon"; import type { EggLapsePhase } from "#phases/egg-lapse-phase"; import { achvs } from "#system/achv"; -import { EggCounterContainer } from "#ui/containers/egg-counter-container"; -import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container"; -import type { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler"; +import { EggCounterContainer } from "#ui/egg-counter-container"; +import type { EggHatchSceneUiHandler } from "#ui/egg-hatch-scene-ui-handler"; +import { PokemonInfoContainer } from "#ui/pokemon-info-container"; import { fixedInt, getFrameMs, randInt } from "#utils/common"; import i18next from "i18next"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; @@ -32,7 +32,7 @@ export class EggHatchPhase extends Phase { private eggCounterContainer: EggCounterContainer; /** The scene handler for egg hatching */ - private eggHatchHandler: EggHatchSceneHandler; + private eggHatchHandler: EggHatchSceneUiHandler; /** The phaser gameobject container that holds everything */ private eggHatchContainer: Phaser.GameObjects.Container; /** The phaser image that is the background */ @@ -92,7 +92,7 @@ export class EggHatchPhase extends Phase { globalScene.fadeOutBgm(undefined, false); - this.eggHatchHandler = globalScene.ui.getHandler() as EggHatchSceneHandler; + this.eggHatchHandler = globalScene.ui.getHandler() as EggHatchSceneUiHandler; this.eggHatchContainer = this.eggHatchHandler.eggHatchContainer; diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index 7d7301bbeca..80750beeb68 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -10,7 +10,7 @@ import { LearnMoveSituation } from "#enums/learn-move-situation"; import { UiMode } from "#enums/ui-mode"; import { cos, sin } from "#field/anims"; import type { PlayerPokemon, Pokemon } from "#field/pokemon"; -import type { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler"; +import type { EvolutionSceneUiHandler } from "#ui/evolution-scene-ui-handler"; import { fixedInt, getFrameMs, randInt } from "#utils/common"; import i18next from "i18next"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; @@ -29,7 +29,7 @@ export class EvolutionPhase extends Phase { private evolution: SpeciesFormEvolution | null; private fusionSpeciesEvolved: boolean; // Whether the evolution is of the fused species private evolutionBgm: AnySound | null; - private evolutionHandler: EvolutionSceneHandler; + private evolutionHandler: EvolutionSceneUiHandler; /** Container for all assets used by the scene. When the scene is cleared, the children within this are destroyed. */ protected evolutionContainer: Phaser.GameObjects.Container; @@ -79,7 +79,7 @@ export class EvolutionPhase extends Phase { * */ private setupEvolutionAssets(): void { - this.evolutionHandler = globalScene.ui.getHandler() as EvolutionSceneHandler; + this.evolutionHandler = globalScene.ui.getHandler() as EvolutionSceneUiHandler; this.evolutionContainer = this.evolutionHandler.evolutionContainer; this.evolutionBaseBg = globalScene.add.image(0, 0, "default_bg").setOrigin(0); diff --git a/src/phases/form-change-phase.ts b/src/phases/form-change-phase.ts index 7521adee6c9..4fb34079367 100644 --- a/src/phases/form-change-phase.ts +++ b/src/phases/form-change-phase.ts @@ -8,7 +8,7 @@ import { UiMode } from "#enums/ui-mode"; import type { PlayerPokemon, Pokemon } from "#field/pokemon"; import { EvolutionPhase } from "#phases/evolution-phase"; import { achvs } from "#system/achv"; -import type { PartyUiHandler } from "#ui/handlers/party-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; import { fixedInt } from "#utils/common"; export class FormChangePhase extends EvolutionPhase { diff --git a/src/phases/game-over-phase.ts b/src/phases/game-over-phase.ts index 57ebd40b559..dd29b97d590 100644 --- a/src/phases/game-over-phase.ts +++ b/src/phases/game-over-phase.ts @@ -16,13 +16,13 @@ import type { EndCardPhase } from "#phases/end-card-phase"; import { achvs, ChallengeAchv } from "#system/achv"; import { ArenaData } from "#system/arena-data"; import { ChallengeData } from "#system/challenge-data"; -import type { SessionSaveData } from "#system/game-data"; import { ModifierData as PersistentModifierData } from "#system/modifier-data"; import { PokemonData } from "#system/pokemon-data"; import { RibbonData, type RibbonFlag } from "#system/ribbons/ribbon-data"; import { awardRibbonsToSpeciesLine } from "#system/ribbons/ribbon-methods"; import { TrainerData } from "#system/trainer-data"; import { trainerConfigs } from "#trainers/trainer-config"; +import type { SessionSaveData } from "#types/save-data"; import { checkSpeciesValidForChallenge, isNuzlockeChallenge } from "#utils/challenge-utils"; import { isLocal, isLocalServerConnected } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; diff --git a/src/phases/learn-move-phase.ts b/src/phases/learn-move-phase.ts index a16e12ba058..4fc38b08d16 100644 --- a/src/phases/learn-move-phase.ts +++ b/src/phases/learn-move-phase.ts @@ -10,8 +10,8 @@ import { UiMode } from "#enums/ui-mode"; import type { Pokemon } from "#field/pokemon"; import type { Move } from "#moves/move"; import { PlayerPartyMemberPokemonPhase } from "#phases/player-party-member-pokemon-phase"; -import { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler"; -import { SummaryUiMode } from "#ui/handlers/summary-ui-handler"; +import { EvolutionSceneUiHandler } from "#ui/evolution-scene-ui-handler"; +import { SummaryUiMode } from "#ui/summary-ui-handler"; import i18next from "i18next"; export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { @@ -47,7 +47,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { } this.messageMode = - globalScene.ui.getHandler() instanceof EvolutionSceneHandler ? UiMode.EVOLUTION_SCENE : UiMode.MESSAGE; + globalScene.ui.getHandler() instanceof EvolutionSceneUiHandler ? UiMode.EVOLUTION_SCENE : UiMode.MESSAGE; globalScene.ui.setMode(this.messageMode); // If the Pokemon has less than 4 moves, the new move is added to the largest empty moveset index // If it has 4 moves, the phase then checks if the player wants to replace the move itself. diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index 6a0c01f857a..df670deaf26 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -289,10 +289,7 @@ export class MysteryEncounterBattlePhase extends Phase { this.doMysteryEncounterBattle(); } - /** - * Gets intro battle message for new battle - * @private - */ + /** Get intro battle message for new battle */ private getBattleMessage(): string { const enemyField = globalScene.getEnemyField(); const encounterMode = globalScene.currentBattle.mysteryEncounter!.encounterMode; @@ -323,8 +320,7 @@ export class MysteryEncounterBattlePhase extends Phase { } /** - * Queues {@linkcode SummonPhase}s for the new battle, and handles trainer animations/dialogue if it's a Trainer battle - * @private + * Queue {@linkcode SummonPhase}s for the new battle and handle trainer animations/dialogue for Trainer battles */ private doMysteryEncounterBattle() { const encounterMode = globalScene.currentBattle.mysteryEncounter!.encounterMode; @@ -401,7 +397,6 @@ export class MysteryEncounterBattlePhase extends Phase { /** * Initiate {@linkcode SummonPhase}s, {@linkcode ScanIvsPhase}, {@linkcode PostSummonPhase}s, etc. - * @private */ private endBattleSetup() { const enemyField = globalScene.getEnemyField(); @@ -450,10 +445,7 @@ export class MysteryEncounterBattlePhase extends Phase { this.end(); } - /** - * Ease in enemy trainer - * @private - */ + /** Ease in enemy trainer */ private showEnemyTrainer(): void { // Show enemy trainer const trainer = globalScene.currentBattle.trainer; diff --git a/src/phases/revival-blessing-phase.ts b/src/phases/revival-blessing-phase.ts index a9dedf4c325..fdb108d62ac 100644 --- a/src/phases/revival-blessing-phase.ts +++ b/src/phases/revival-blessing-phase.ts @@ -3,8 +3,8 @@ import { SwitchType } from "#enums/switch-type"; import { UiMode } from "#enums/ui-mode"; import type { PlayerPokemon } from "#field/pokemon"; import { BattlePhase } from "#phases/battle-phase"; -import type { PartyOption } from "#ui/handlers/party-ui-handler"; -import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import type { PartyOption } from "#ui/party-ui-handler"; +import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import { isNullOrUndefined, toDmgValue } from "#utils/common"; import i18next from "i18next"; diff --git a/src/phases/select-biome-phase.ts b/src/phases/select-biome-phase.ts index 3276c34306c..21c0cfade94 100644 --- a/src/phases/select-biome-phase.ts +++ b/src/phases/select-biome-phase.ts @@ -5,7 +5,7 @@ import { ChallengeType } from "#enums/challenge-type"; import { UiMode } from "#enums/ui-mode"; import { MapModifier, MoneyInterestModifier } from "#modifiers/modifier"; import { BattlePhase } from "#phases/battle-phase"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import { applyChallenges } from "#utils/challenge-utils"; import { BooleanHolder, randSeedInt } from "#utils/common"; diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts index 51adeb21af0..3c378a95b2a 100644 --- a/src/phases/select-modifier-phase.ts +++ b/src/phases/select-modifier-phase.ts @@ -24,9 +24,9 @@ import { TmModifierType, } from "#modifiers/modifier-type"; import { BattlePhase } from "#phases/battle-phase"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; -import { SHOP_OPTIONS_ROW_LIMIT } from "#ui/handlers/modifier-select-ui-handler"; -import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import { SHOP_OPTIONS_ROW_LIMIT } from "#ui/modifier-select-ui-handler"; +import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import { isNullOrUndefined, NumberHolder } from "#utils/common"; import i18next from "i18next"; diff --git a/src/phases/select-starter-phase.ts b/src/phases/select-starter-phase.ts index 50c06f96a77..a08394e3acb 100644 --- a/src/phases/select-starter-phase.ts +++ b/src/phases/select-starter-phase.ts @@ -7,8 +7,8 @@ import { ChallengeType } from "#enums/challenge-type"; import type { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { overrideHeldItems, overrideModifiers } from "#modifiers/modifier"; -import { SaveSlotUiMode } from "#ui/handlers/save-slot-select-ui-handler"; -import type { Starter } from "#ui/handlers/starter-select-ui-handler"; +import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler"; +import type { Starter } from "#ui/starter-select-ui-handler"; import { applyChallenges } from "#utils/challenge-utils"; import { isNullOrUndefined } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; diff --git a/src/phases/switch-phase.ts b/src/phases/switch-phase.ts index 8b03f5ec5ce..83a699b6b08 100644 --- a/src/phases/switch-phase.ts +++ b/src/phases/switch-phase.ts @@ -3,7 +3,7 @@ import { DynamicPhaseType } from "#enums/dynamic-phase-type"; import { SwitchType } from "#enums/switch-type"; import { UiMode } from "#enums/ui-mode"; import { BattlePhase } from "#phases/battle-phase"; -import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import { PartyOption, PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; /** * Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase} diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index fd12ec3bd6b..d422766bf09 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -14,10 +14,10 @@ import { Unlockables } from "#enums/unlockables"; import { getBiomeKey } from "#field/arena"; import type { Modifier } from "#modifiers/modifier"; import { getDailyRunStarterModifiers, regenerateModifierPoolThresholds } from "#modifiers/modifier-type"; -import type { SessionSaveData } from "#system/game-data"; import { vouchers } from "#system/voucher"; -import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import { SaveSlotUiMode } from "#ui/handlers/save-slot-select-ui-handler"; +import type { SessionSaveData } from "#types/save-data"; +import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import { SaveSlotUiMode } from "#ui/save-slot-select-ui-handler"; import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#utils/common"; import i18next from "i18next"; diff --git a/src/plugins/api/pokerogue-daily-api.ts b/src/plugins/api/pokerogue-daily-api.ts index dfde4720730..5ea3846e60e 100644 --- a/src/plugins/api/pokerogue-daily-api.ts +++ b/src/plugins/api/pokerogue-daily-api.ts @@ -1,6 +1,6 @@ import { ApiBase } from "#api/api-base"; import type { GetDailyRankingsPageCountRequest, GetDailyRankingsRequest } from "#types/api/pokerogue-daily-api"; -import type { RankingEntry } from "#ui/containers/daily-run-scoreboard"; +import type { RankingEntry } from "#ui/daily-run-scoreboard"; /** * A wrapper for daily-run PokéRogue API requests. diff --git a/src/plugins/api/pokerogue-session-savedata-api.ts b/src/plugins/api/pokerogue-session-savedata-api.ts index 87960339671..e1c67ef7245 100644 --- a/src/plugins/api/pokerogue-session-savedata-api.ts +++ b/src/plugins/api/pokerogue-session-savedata-api.ts @@ -1,5 +1,4 @@ import { ApiBase } from "#api/api-base"; -import type { SessionSaveData } from "#system/game-data"; import type { ClearSessionSavedataRequest, ClearSessionSavedataResponse, @@ -8,6 +7,7 @@ import type { NewClearSessionSavedataRequest, UpdateSessionSavedataRequest, } from "#types/api/pokerogue-session-save-data-api"; +import type { SessionSaveData } from "#types/save-data"; /** * A wrapper for PokéRogue session savedata API requests. diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 3442748c9ab..8c2a1219245 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1,6 +1,5 @@ import { pokerogueApi } from "#api/pokerogue-api"; import { clientSessionId, loggedInUser, updateUserInfo } from "#app/account"; -import type { PokeballCounts } from "#app/battle-scene"; import { defaultStarterSpecies, saveKey } from "#app/constants"; import { getGameMode } from "#app/game-mode"; import { globalScene } from "#app/global-scene"; @@ -24,11 +23,9 @@ import { Device } from "#enums/devices"; import { DexAttr } from "#enums/dex-attr"; import { GameDataType } from "#enums/game-data-type"; import { GameModes } from "#enums/game-modes"; -import type { MoveId } from "#enums/move-id"; import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { Nature } from "#enums/nature"; import { PlayerGender } from "#enums/player-gender"; -import type { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; import { StatusEffect } from "#enums/status-effect"; import { TrainerVariant } from "#enums/trainer-variant"; @@ -62,7 +59,20 @@ import { import { VoucherType, vouchers } from "#system/voucher"; import { trainerConfigs } from "#trainers/trainer-config"; import type { DexData, DexEntry } from "#types/dex-data"; -import { RUN_HISTORY_LIMIT } from "#ui/handlers/run-history-ui-handler"; +import type { + AchvUnlocks, + DexAttrProps, + RunHistoryData, + SeenDialogues, + SessionSaveData, + StarterData, + SystemSaveData, + TutorialFlags, + Unlocks, + VoucherCounts, + VoucherUnlocks, +} from "#types/save-data"; +import { RUN_HISTORY_LIMIT } from "#ui/run-history-ui-handler"; import { applyChallenges } from "#utils/challenge-utils"; import { executeIf, fixedInt, isLocal, NumberHolder, randInt, randSeedItem } from "#utils/common"; import { decrypt, encrypt } from "#utils/data"; @@ -94,132 +104,6 @@ function getDataTypeKey(dataType: GameDataType, slotId = 0): string { } } -// TODO: Move all these exported interfaces to @types -export interface SystemSaveData { - trainerId: number; - secretId: number; - gender: PlayerGender; - dexData: DexData; - starterData: StarterData; - gameStats: GameStats; - unlocks: Unlocks; - achvUnlocks: AchvUnlocks; - voucherUnlocks: VoucherUnlocks; - voucherCounts: VoucherCounts; - eggs: EggData[]; - gameVersion: string; - timestamp: number; - eggPity: number[]; - unlockPity: number[]; -} - -export interface SessionSaveData { - seed: string; - playTime: number; - gameMode: GameModes; - party: PokemonData[]; - enemyParty: PokemonData[]; - modifiers: PersistentModifierData[]; - enemyModifiers: PersistentModifierData[]; - arena: ArenaData; - pokeballCounts: PokeballCounts; - money: number; - score: number; - waveIndex: number; - battleType: BattleType; - trainer: TrainerData; - gameVersion: string; - /** The player-chosen name of the run */ - name: string; - timestamp: number; - challenges: ChallengeData[]; - mysteryEncounterType: MysteryEncounterType | -1; // Only defined when current wave is ME, - mysteryEncounterSaveData: MysteryEncounterSaveData; - /** - * Counts the amount of pokemon fainted in your party during the current arena encounter. - */ - playerFaints: number; -} - -interface Unlocks { - [key: number]: boolean; -} - -export interface AchvUnlocks { - [key: string]: number; -} - -export interface VoucherUnlocks { - [key: string]: number; -} - -export interface VoucherCounts { - [type: string]: number; -} - -export type StarterMoveset = [MoveId] | [MoveId, MoveId] | [MoveId, MoveId, MoveId] | [MoveId, MoveId, MoveId, MoveId]; - -export interface StarterFormMoveData { - [key: number]: StarterMoveset; -} - -export interface StarterMoveData { - [key: number]: StarterMoveset | StarterFormMoveData; -} - -export interface StarterAttributes { - nature?: number; - ability?: number; - variant?: number; - form?: number; - female?: boolean; - shiny?: boolean; - favorite?: boolean; - nickname?: string; - tera?: PokemonType; -} - -export interface DexAttrProps { - shiny: boolean; - female: boolean; - variant: Variant; - formIndex: number; -} - -export type RunHistoryData = Record; - -export interface RunEntry { - entry: SessionSaveData; - isVictory: boolean; - /*Automatically set to false at the moment - implementation TBD*/ - isFavorite: boolean; -} - -export interface StarterDataEntry { - moveset: StarterMoveset | StarterFormMoveData | null; - eggMoves: number; - candyCount: number; - friendship: number; - abilityAttr: number; - passiveAttr: number; - valueReduction: number; - classicWinCount: number; -} - -export interface StarterData { - [key: number]: StarterDataEntry; -} - -// TODO: Rework into a bitmask -export type TutorialFlags = { - [key in Tutorial]: boolean; -}; - -// TODO: Rework into a bitmask -export interface SeenDialogues { - [key: string]: boolean; -} - const systemShortKeys = { seenAttr: "$sa", caughtAttr: "$ca", @@ -2002,9 +1886,7 @@ export class GameData { }); } - /** - * Checks whether the root species of a given {@PokemonSpecies} has been unlocked in the dex - */ + /** Return whether the root species of a given `PokemonSpecies` has been unlocked in the dex */ isRootSpeciesUnlocked(species: PokemonSpecies): boolean { return !!this.dexData[species.getRootSpeciesId()]?.caughtAttr; } diff --git a/src/system/settings/settings-language.ts b/src/system/settings/settings-language.ts new file mode 100644 index 00000000000..3fd90477e65 --- /dev/null +++ b/src/system/settings/settings-language.ts @@ -0,0 +1,101 @@ +import { globalScene } from "#app/global-scene"; +import type { SettingsDisplayUiHandler } from "#ui/settings-display-ui-handler"; +import i18next from "i18next"; + +const cancelHandler = () => { + globalScene.ui.revertMode(); + const handler = globalScene.ui.getHandler(); + // Reset the cursor to the current language, if in the settings menu + if (handler && typeof (handler as SettingsDisplayUiHandler).setOptionCursor === "function") { + (handler as SettingsDisplayUiHandler).setOptionCursor(-1, 0, true); + } +}; + +const changeLocaleHandler = (locale: string): boolean => { + try { + i18next.changeLanguage(locale); + localStorage.setItem("prLang", locale); + cancelHandler(); + // Reload the whole game to apply the new locale since also some constants are translated + window.location.reload(); + return true; + } catch (error) { + console.error("Error changing locale:", error); + return false; + } +}; + +export const languageOptions = [ + { + label: "English", + handler: () => changeLocaleHandler("en"), + }, + { + label: "Español (ES)", + handler: () => changeLocaleHandler("es-ES"), + }, + { + label: "Español (LATAM)", + handler: () => changeLocaleHandler("es-MX"), + }, + { + label: "Français", + handler: () => changeLocaleHandler("fr"), + }, + { + label: "Deutsch", + handler: () => changeLocaleHandler("de"), + }, + { + label: "Italiano", + handler: () => changeLocaleHandler("it"), + }, + { + label: "Português (BR)", + handler: () => changeLocaleHandler("pt-BR"), + }, + { + label: "한국어", + handler: () => changeLocaleHandler("ko"), + }, + { + label: "日本語", + handler: () => changeLocaleHandler("ja"), + }, + { + label: "简体中文", + handler: () => changeLocaleHandler("zh-CN"), + }, + { + label: "繁體中文", + handler: () => changeLocaleHandler("zh-TW"), + }, + { + label: "Català (Needs Help)", + handler: () => changeLocaleHandler("ca"), + }, + { + label: "Türkçe (Needs Help)", + handler: () => changeLocaleHandler("tr"), + }, + { + label: "Русский (Needs Help)", + handler: () => changeLocaleHandler("ru"), + }, + { + label: "Dansk (Needs Help)", + handler: () => changeLocaleHandler("da"), + }, + { + label: "Română (Needs Help)", + handler: () => changeLocaleHandler("ro"), + }, + { + label: "Tagalog (Needs Help)", + handler: () => changeLocaleHandler("tl"), + }, + { + label: i18next.t("settings:back"), + handler: () => cancelHandler(), + }, +]; diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index cf3a5fb0eee..78b6044b0fc 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -6,10 +6,10 @@ import { PlayerGender } from "#enums/player-gender"; import { ShopCursorTarget } from "#enums/shop-cursor-target"; import { UiMode } from "#enums/ui-mode"; import { CandyUpgradeNotificationChangedEvent } from "#events/battle-scene"; -import type { SettingsUiHandler } from "#ui/settings-ui-handler"; import { updateWindowType } from "#ui/ui-theme"; import { isLocal } from "#utils/common"; import i18next from "i18next"; +import { languageOptions } from "./settings-language"; const VOLUME_OPTIONS: SettingOption[] = [ { @@ -120,6 +120,14 @@ export interface Setting { default: number; type: SettingType; requireReload?: boolean; + /** + * Specifies the behavior when navigating left/right at the boundaries of the option + * + * - `true`: the cursor will stay on the boundary instead of moving + * - `false`: the cursor will wrap to the other end of the options list + * @defaultValue `false` + */ + clamp?: boolean; /** Whether the setting can be activated or not */ activatable?: boolean; /** Determines whether the setting should be hidden from the UI */ @@ -230,6 +238,7 @@ export const Setting: Array = [ ], default: 3, type: SettingType.GENERAL, + clamp: false, }, { key: SettingKeys.HP_Bar_Speed, @@ -639,6 +648,7 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 5, type: SettingType.AUDIO, + clamp: true, }, { key: SettingKeys.BGM_Volume, @@ -646,6 +656,7 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 10, type: SettingType.AUDIO, + clamp: true, }, { key: SettingKeys.Field_Volume, @@ -653,6 +664,7 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 10, type: SettingType.AUDIO, + clamp: true, }, { key: SettingKeys.SE_Volume, @@ -660,6 +672,7 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 10, type: SettingType.AUDIO, + clamp: true, }, { key: SettingKeys.UI_Volume, @@ -667,6 +680,7 @@ export const Setting: Array = [ options: VOLUME_OPTIONS, default: 10, type: SettingType.AUDIO, + clamp: true, }, { key: SettingKeys.Battle_Music, @@ -897,98 +911,8 @@ export function setSetting(setting: string, value: number): boolean { break; case SettingKeys.Language: if (value && globalScene.ui) { - const cancelHandler = () => { - globalScene.ui.revertMode(); - (globalScene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true); - }; - const changeLocaleHandler = (locale: string): boolean => { - try { - i18next.changeLanguage(locale); - localStorage.setItem("prLang", locale); - cancelHandler(); - // Reload the whole game to apply the new locale since also some constants are translated - window.location.reload(); - return true; - } catch (error) { - console.error("Error changing locale:", error); - return false; - } - }; globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { - options: [ - { - label: "English", - handler: () => changeLocaleHandler("en"), - }, - { - label: "Español (ES)", - handler: () => changeLocaleHandler("es-ES"), - }, - { - label: "Español (LATAM)", - handler: () => changeLocaleHandler("es-MX"), - }, - { - label: "Français", - handler: () => changeLocaleHandler("fr"), - }, - { - label: "Deutsch", - handler: () => changeLocaleHandler("de"), - }, - { - label: "Italiano", - handler: () => changeLocaleHandler("it"), - }, - { - label: "Português (BR)", - handler: () => changeLocaleHandler("pt-BR"), - }, - { - label: "한국어", - handler: () => changeLocaleHandler("ko"), - }, - { - label: "日本語", - handler: () => changeLocaleHandler("ja"), - }, - { - label: "简体中文", - handler: () => changeLocaleHandler("zh-CN"), - }, - { - label: "繁體中文", - handler: () => changeLocaleHandler("zh-TW"), - }, - { - label: "Català (Needs Help)", - handler: () => changeLocaleHandler("ca"), - }, - { - label: "Türkçe (Needs Help)", - handler: () => changeLocaleHandler("tr"), - }, - { - label: "Русский (Needs Help)", - handler: () => changeLocaleHandler("ru"), - }, - { - label: "Dansk (Needs Help)", - handler: () => changeLocaleHandler("da"), - }, - { - label: "Română (Needs Help)", - handler: () => changeLocaleHandler("ro"), - }, - { - label: "Tagalog (Needs Help)", - handler: () => changeLocaleHandler("tl"), - }, - { - label: i18next.t("settings:back"), - handler: () => cancelHandler(), - }, - ], + options: languageOptions, maxOptions: 7, }); return false; diff --git a/src/system/version-migration/version-converter.ts b/src/system/version-migration/version-converter.ts index 6dde611ce84..269e577ca3f 100644 --- a/src/system/version-migration/version-converter.ts +++ b/src/system/version-migration/version-converter.ts @@ -1,7 +1,7 @@ /** biome-ignore-all lint/performance/noNamespaceImport: Convenience */ import { version } from "#package.json"; -import type { SessionSaveData, SystemSaveData } from "#system/game-data"; +import type { SessionSaveData, SystemSaveData } from "#types/save-data"; import type { SessionSaveMigrator } from "#types/session-save-migrator"; import type { SettingsSaveMigrator } from "#types/settings-save-migrator"; import type { SystemSaveMigrator } from "#types/system-save-migrator"; diff --git a/src/system/version-migration/versions/v1_0_4.ts b/src/system/version-migration/versions/v1_0_4.ts index 6d65df29970..8229b9320d5 100644 --- a/src/system/version-migration/versions/v1_0_4.ts +++ b/src/system/version-migration/versions/v1_0_4.ts @@ -3,8 +3,8 @@ import { allSpecies } from "#data/data-lists"; import { CustomPokemonData } from "#data/pokemon-data"; import { AbilityAttr } from "#enums/ability-attr"; import { DexAttr } from "#enums/dex-attr"; -import type { SessionSaveData, SystemSaveData } from "#system/game-data"; import { SettingKeys } from "#system/settings"; +import type { SessionSaveData, SystemSaveData } from "#types/save-data"; import type { SessionSaveMigrator } from "#types/session-save-migrator"; import type { SettingsSaveMigrator } from "#types/settings-save-migrator"; import type { SystemSaveMigrator } from "#types/system-save-migrator"; diff --git a/src/system/version-migration/versions/v1_10_0.ts b/src/system/version-migration/versions/v1_10_0.ts index 5c13acd4508..eab0b0cc78e 100644 --- a/src/system/version-migration/versions/v1_10_0.ts +++ b/src/system/version-migration/versions/v1_10_0.ts @@ -2,7 +2,7 @@ import type { BattlerIndex } from "#enums/battler-index"; import type { MoveId } from "#enums/move-id"; import type { MoveResult } from "#enums/move-result"; import { MoveUseMode } from "#enums/move-use-mode"; -import type { SessionSaveData } from "#system/game-data"; +import type { SessionSaveData } from "#types/save-data"; import type { SessionSaveMigrator } from "#types/session-save-migrator"; import type { TurnMove } from "#types/turn-move"; diff --git a/src/system/version-migration/versions/v1_7_0.ts b/src/system/version-migration/versions/v1_7_0.ts index 69c640756ea..6d365cf31ac 100644 --- a/src/system/version-migration/versions/v1_7_0.ts +++ b/src/system/version-migration/versions/v1_7_0.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import { DexAttr } from "#enums/dex-attr"; -import type { SessionSaveData, SystemSaveData } from "#system/game-data"; +import type { SessionSaveData, SystemSaveData } from "#types/save-data"; import type { SessionSaveMigrator } from "#types/session-save-migrator"; import type { SystemSaveMigrator } from "#types/system-save-migrator"; import { isNullOrUndefined } from "#utils/common"; diff --git a/src/system/version-migration/versions/v1_8_3.ts b/src/system/version-migration/versions/v1_8_3.ts index 4907b4e5e57..0d6fd87a56c 100644 --- a/src/system/version-migration/versions/v1_8_3.ts +++ b/src/system/version-migration/versions/v1_8_3.ts @@ -1,6 +1,6 @@ import { DexAttr } from "#enums/dex-attr"; import { SpeciesId } from "#enums/species-id"; -import type { SystemSaveData } from "#system/game-data"; +import type { SystemSaveData } from "#types/save-data"; import type { SystemSaveMigrator } from "#types/system-save-migrator"; import { getPokemonSpecies } from "#utils/pokemon-utils"; diff --git a/src/system/version-migration/versions/v1_9_0.ts b/src/system/version-migration/versions/v1_9_0.ts index 60e299ed458..eee60571884 100644 --- a/src/system/version-migration/versions/v1_9_0.ts +++ b/src/system/version-migration/versions/v1_9_0.ts @@ -1,7 +1,7 @@ import { MoveId } from "#enums/move-id"; import { PokemonMove } from "#moves/pokemon-move"; -import type { SessionSaveData } from "#system/game-data"; import type { PokemonData } from "#system/pokemon-data"; +import type { SessionSaveData } from "#types/save-data"; import type { SessionSaveMigrator } from "#types/session-save-migrator"; /** diff --git a/src/touch-controls.ts b/src/touch-controls.ts index 370b1748653..d031af9ef4c 100644 --- a/src/touch-controls.ts +++ b/src/touch-controls.ts @@ -5,9 +5,9 @@ import type Phaser from "phaser"; const repeatInputDelayMillis = 250; export class TouchControl { - events: Phaser.Events.EventEmitter; + readonly events: Phaser.Events.EventEmitter; private buttonLock: string[] = []; - private inputInterval: NodeJS.Timeout[] = []; + private readonly inputInterval: NodeJS.Timeout[] = []; /** Whether touch controls are disabled */ private disabled = false; /** Whether the last touch event has finished before disabling */ @@ -61,12 +61,46 @@ export class TouchControl { * event, removes the keydown state, and removes the 'active' class from the node and the last touched element. */ bindKey(node: HTMLElement, key: string) { + node.addEventListener("touchstart", (event: TouchEvent) => { + // Handle touch events for touch devices + this.touchButtonDown(node, key); + event.preventDefault(); + + // prevent pointer event from also firing (undefined just sets presence of custom attribute) + if (event.currentTarget instanceof HTMLElement) { + event.currentTarget.dataset.skipPointerEvent = undefined; + } + }); node.addEventListener("pointerdown", event => { + const currentTarget = event.currentTarget; + if (currentTarget instanceof HTMLElement && "skipPointerDown" in currentTarget.dataset) { + return; + } event.preventDefault(); this.touchButtonDown(node, key); }); + node.addEventListener("touchcancel", (event: TouchEvent) => { + if (event.currentTarget instanceof HTMLElement && "skipPointerDown" in event.currentTarget.dataset) { + delete event.currentTarget.dataset.skipPointerEvent; + } + }); + + node.addEventListener("touchend", (event: TouchEvent) => { + event.preventDefault(); + this.touchButtonUp(node, key, event.target?.["id"]); + if (event.currentTarget instanceof HTMLElement && "skipPointerDown" in event.currentTarget.dataset) { + // allow pointer event to once again fire + delete event.currentTarget.dataset.skipPointerEvent; + event.currentTarget.dataset.skipPointerUp = undefined; + } + }); + node.addEventListener("pointerup", event => { + if (event.currentTarget instanceof HTMLElement && "skipPointerUp" in event.currentTarget.dataset) { + delete event.currentTarget.dataset.skipPointerUp; + return; + } event.preventDefault(); this.touchButtonUp(node, key, event.target?.["id"]); }); @@ -143,7 +177,7 @@ export class TouchControl { * {@link https://stackoverflow.com/a/39778831/4622620|Source} * * Prevent zoom on specified element - * @param {HTMLElement} element + * @param element */ preventElementZoom(element: HTMLElement | null): void { if (!element) { diff --git a/src/tutorial.ts b/src/tutorial.ts index 5ab0be116f8..018d0927da0 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -1,8 +1,8 @@ import { globalScene } from "#app/global-scene"; import Overrides from "#app/overrides"; import { UiMode } from "#enums/ui-mode"; -import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; -import type { UiHandler } from "#ui/handlers/ui-handler"; +import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; +import type { UiHandler } from "#ui/ui-handler"; import i18next from "i18next"; export enum Tutorial { diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 34a08db8fbc..fd7883d3136 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -3,16 +3,16 @@ import type { InputsController } from "#app/inputs-controller"; import { Button } from "#enums/buttons"; import { UiMode } from "#enums/ui-mode"; import { Setting, SettingKeys, settingIndex } from "#system/settings"; -import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler"; -import type { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler"; -import { RunInfoUiHandler } from "#ui/handlers/run-info-ui-handler"; -import { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler"; +import type { MessageUiHandler } from "#ui/message-ui-handler"; +import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler"; +import { PokedexUiHandler } from "#ui/pokedex-ui-handler"; +import { RunInfoUiHandler } from "#ui/run-info-ui-handler"; import { SettingsAudioUiHandler } from "#ui/settings-audio-ui-handler"; import { SettingsDisplayUiHandler } from "#ui/settings-display-ui-handler"; import { SettingsGamepadUiHandler } from "#ui/settings-gamepad-ui-handler"; import { SettingsKeyboardUiHandler } from "#ui/settings-keyboard-ui-handler"; import { SettingsUiHandler } from "#ui/settings-ui-handler"; +import { StarterSelectUiHandler } from "#ui/starter-select-ui-handler"; import Phaser from "phaser"; type ActionKeys = Record void>; diff --git a/src/ui/battle-info/enemy-battle-info.ts b/src/ui/battle-info/enemy-battle-info.ts index ad72afedc38..1a16a1dd934 100644 --- a/src/ui/battle-info/enemy-battle-info.ts +++ b/src/ui/battle-info/enemy-battle-info.ts @@ -3,9 +3,9 @@ import { Stat } from "#enums/stat"; import { TextStyle } from "#enums/text-style"; import { UiTheme } from "#enums/ui-theme"; import type { EnemyPokemon } from "#field/pokemon"; +import { BattleFlyout } from "#ui/battle-flyout"; import type { BattleInfoParamList } from "#ui/battle-info"; import { BattleInfo } from "#ui/battle-info"; -import { BattleFlyout } from "#ui/containers/battle-flyout"; import { addTextObject } from "#ui/text"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import { getLocalizedSpriteKey } from "#utils/common"; diff --git a/src/ui/containers/arena-flyout.ts b/src/ui/containers/arena-flyout.ts index 3555694760d..a73846de1ac 100644 --- a/src/ui/containers/arena-flyout.ts +++ b/src/ui/containers/arena-flyout.ts @@ -15,8 +15,8 @@ import { } from "#events/arena"; import type { TurnEndEvent } from "#events/battle-scene"; import { BattleSceneEventType } from "#events/battle-scene"; -import { TimeOfDayWidget } from "#ui/containers/time-of-day-widget"; import { addTextObject } from "#ui/text"; +import { TimeOfDayWidget } from "#ui/time-of-day-widget"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import { fixedInt } from "#utils/common"; import { toCamelCase, toTitleCase } from "#utils/strings"; diff --git a/src/ui/containers/bgm-bar.ts b/src/ui/containers/bgm-bar.ts index f24f372a804..9c9e761e26b 100644 --- a/src/ui/containers/bgm-bar.ts +++ b/src/ui/containers/bgm-bar.ts @@ -53,7 +53,7 @@ export class BgmBar extends Phaser.GameObjects.Container { /* * Set the BGM Name to the BGM bar. - * @param {string} bgmName The name of the BGM to set. + * @param bgmName The name of the BGM to set. */ setBgmToBgmBar(bgmName: string): void { this.musicText.setText(`${i18next.t("bgmName:music")}${this.getRealBgmName(bgmName)}`); @@ -71,7 +71,7 @@ export class BgmBar extends Phaser.GameObjects.Container { /* Show or hide the BGM bar. - @param {boolean} visible Whether to show or hide the BGM bar. + @param visible Whether to show or hide the BGM bar. */ public toggleBgmBar(visible: boolean): void { /* diff --git a/src/ui/containers/daily-run-scoreboard.ts b/src/ui/containers/daily-run-scoreboard.ts index 9391d02859c..456c8edde01 100644 --- a/src/ui/containers/daily-run-scoreboard.ts +++ b/src/ui/containers/daily-run-scoreboard.ts @@ -202,8 +202,8 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { * The method fetches the total page count if necessary, followed by fetching the rankings for the specified category * and page. It updates the UI with the fetched rankings or shows an appropriate message if no rankings are found. * - * @param {ScoreboardCategory} [category=this.category] - The category to fetch rankings for. Defaults to the current category. - * @param {number} [page=this.page] - The page number to fetch. Defaults to the current page. + * @param [category=this.category] - The category to fetch rankings for. Defaults to the current category. + * @param [page=this.page] - The page number to fetch. Defaults to the current page. */ update(category: ScoreboardCategory = this.category, page: number = this.page) { if (this.isUpdating) { @@ -249,7 +249,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { /** * Sets the state of the navigation buttons. - * @param {boolean} [enabled=true] - Whether the buttons should be enabled or disabled. + * @param [enabled=true] - Whether the buttons should be enabled or disabled. */ setButtonsState(enabled = true) { const buttons = [ diff --git a/src/ui/containers/dropdown.ts b/src/ui/containers/dropdown.ts index bf589085d2e..2244aa0e5ce 100644 --- a/src/ui/containers/dropdown.ts +++ b/src/ui/containers/dropdown.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; -import { ScrollBar } from "#ui/containers/scroll-bar"; +import { ScrollBar } from "#ui/scroll-bar"; import { addTextObject } from "#ui/text"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import i18next from "i18next"; diff --git a/src/ui/containers/egg-counter-container.ts b/src/ui/containers/egg-counter-container.ts index 811b6b3bc3a..385480fc91d 100644 --- a/src/ui/containers/egg-counter-container.ts +++ b/src/ui/containers/egg-counter-container.ts @@ -2,14 +2,11 @@ import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; import type { EggCountChangedEvent } from "#events/egg"; import { EggEventType } from "#events/egg"; -import type { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler"; +import type { EggHatchSceneUiHandler } from "#ui/egg-hatch-scene-ui-handler"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; -/** - * A container that displays the count of hatching eggs. - * @extends Phaser.GameObjects.Container - */ +/** A container that displays the count of hatching eggs */ export class EggCounterContainer extends Phaser.GameObjects.Container { private readonly WINDOW_DEFAULT_WIDTH = 37; private readonly WINDOW_MEDIUM_WIDTH = 42; @@ -27,7 +24,7 @@ export class EggCounterContainer extends Phaser.GameObjects.Container { super(globalScene, 0, 0); this.eggCount = eggCount; - const uiHandler = globalScene.ui.getHandler() as EggHatchSceneHandler; + const uiHandler = globalScene.ui.getHandler() as EggHatchSceneUiHandler; uiHandler.eventTarget.addEventListener(EggEventType.EGG_COUNT_CHANGED, this.onEggCountChangedEvent); this.setup(); diff --git a/src/ui/containers/filter-bar.ts b/src/ui/containers/filter-bar.ts index bbca38c3f53..3f164c4fcbb 100644 --- a/src/ui/containers/filter-bar.ts +++ b/src/ui/containers/filter-bar.ts @@ -2,9 +2,9 @@ import { globalScene } from "#app/global-scene"; import type { DropDownColumn } from "#enums/drop-down-column"; import { TextStyle } from "#enums/text-style"; import type { UiTheme } from "#enums/ui-theme"; -import type { DropDown } from "#ui/containers/dropdown"; -import { DropDownType } from "#ui/containers/dropdown"; -import type { StarterContainer } from "#ui/containers/starter-container"; +import type { DropDown } from "#ui/dropdown"; +import { DropDownType } from "#ui/dropdown"; +import type { StarterContainer } from "#ui/starter-container"; import { addTextObject, getTextColor } from "#ui/text"; import { addWindow, WindowVariant } from "#ui/ui-theme"; diff --git a/src/ui/containers/filter-text.ts b/src/ui/containers/filter-text.ts index 0d15aca8530..8601a86defa 100644 --- a/src/ui/containers/filter-text.ts +++ b/src/ui/containers/filter-text.ts @@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; import type { UiTheme } from "#enums/ui-theme"; -import type { StarterContainer } from "#ui/containers/starter-container"; -import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; +import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; +import type { StarterContainer } from "#ui/starter-container"; import { addTextObject, getTextColor } from "#ui/text"; import type { UI } from "#ui/ui"; import { addWindow, WindowVariant } from "#ui/ui-theme"; diff --git a/src/ui/containers/hatched-pokemon-container.ts b/src/ui/containers/hatched-pokemon-container.ts index 4ed67477a3f..b1bc66c21ec 100644 --- a/src/ui/containers/hatched-pokemon-container.ts +++ b/src/ui/containers/hatched-pokemon-container.ts @@ -4,8 +4,8 @@ import { Gender } from "#data/gender"; import type { PokemonSpecies } from "#data/pokemon-species"; import { DexAttr } from "#enums/dex-attr"; import { getVariantTint } from "#sprites/variant"; -import type { PokemonIconAnimHandler } from "#ui/handlers/pokemon-icon-anim-handler"; -import { PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; +import type { PokemonIconAnimHelper } from "#ui/pokemon-icon-anim-helper"; +import { PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; /** * A container for a Pokemon's sprite and icons to get displayed in the egg summary screen @@ -81,9 +81,9 @@ export class HatchedPokemonContainer extends Phaser.GameObjects.Container { * Animates the pokemon icon if it has a new form or shiny variant * * @param hatchData the {@linkcode EggHatchData} to base the icons on - * @param iconAnimHandler the {@linkcode PokemonIconAnimHandler} to use to animate the sprites + * @param iconAnimHandler the {@linkcode PokemonIconAnimHelper} to use to animate the sprites */ - updateAndAnimate(hatchData: EggHatchData, iconAnimHandler: PokemonIconAnimHandler) { + updateAndAnimate(hatchData: EggHatchData, iconAnimHandler: PokemonIconAnimHelper) { const displayPokemon = hatchData.pokemon; this.species = displayPokemon.species; diff --git a/src/ui/containers/pokemon-hatch-info-container.ts b/src/ui/containers/pokemon-hatch-info-container.ts index 8ddd9df9836..ad09eb39d42 100644 --- a/src/ui/containers/pokemon-hatch-info-container.ts +++ b/src/ui/containers/pokemon-hatch-info-container.ts @@ -9,11 +9,11 @@ import { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; import { TextStyle } from "#enums/text-style"; import type { PlayerPokemon } from "#field/pokemon"; -import { PokemonInfoContainer } from "#ui/containers/pokemon-info-container"; import { addTextObject } from "#ui/text"; import { padInt, rgbHexToRgba } from "#utils/common"; import { getPokemonSpeciesForm } from "#utils/pokemon-utils"; import { argbFromRgba } from "@material/material-color-utilities"; +import { PokemonInfoContainer } from "./pokemon-info-container"; /** * Class for the hatch info summary of each pokemon diff --git a/src/ui/containers/pokemon-info-container.ts b/src/ui/containers/pokemon-info-container.ts index 2b214229992..3b6e5bc2fc1 100644 --- a/src/ui/containers/pokemon-info-container.ts +++ b/src/ui/containers/pokemon-info-container.ts @@ -6,15 +6,15 @@ import { PokemonType } from "#enums/pokemon-type"; import { TextStyle } from "#enums/text-style"; import type { Pokemon } from "#field/pokemon"; import { getVariantTint } from "#sprites/variant"; -import type { StarterDataEntry } from "#system/game-data"; import type { DexEntry } from "#types/dex-data"; -import { StatsContainer } from "#ui/containers/stats-container"; -import { ConfirmUiHandler } from "#ui/handlers/confirm-ui-handler"; +import type { StarterDataEntry } from "#types/save-data"; +import { ConfirmUiHandler } from "#ui/confirm-ui-handler"; import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { fixedInt, getShinyDescriptor } from "#utils/common"; import i18next from "i18next"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; +import { StatsContainer } from "./stats-container"; interface LanguageSetting { infoContainerTextSize: string; diff --git a/src/ui/containers/saving-icon-handler.ts b/src/ui/containers/saving-icon-handler.ts index 00c8b8b526c..aad37bca97f 100644 --- a/src/ui/containers/saving-icon-handler.ts +++ b/src/ui/containers/saving-icon-handler.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import { fixedInt } from "#utils/common"; -export class SavingIconHandler extends Phaser.GameObjects.Container { +export class SavingIconContainer extends Phaser.GameObjects.Container { private icon: Phaser.GameObjects.Sprite; private animActive: boolean; diff --git a/src/ui/handlers/abstract-binding-ui-handler.ts b/src/ui/handlers/abstract-binding-ui-handler.ts index d106ff6f914..6b747a10d2b 100644 --- a/src/ui/handlers/abstract-binding-ui-handler.ts +++ b/src/ui/handlers/abstract-binding-ui-handler.ts @@ -2,9 +2,9 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { NavigationManager } from "#ui/navigation-menu"; import { addTextObject, getTextColor } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; diff --git a/src/ui/handlers/abstract-option-select-ui-handler.ts b/src/ui/handlers/abstract-option-select-ui-handler.ts index 1e102010e4a..b86d5c33a0d 100644 --- a/src/ui/handlers/abstract-option-select-ui-handler.ts +++ b/src/ui/handlers/abstract-option-select-ui-handler.ts @@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addBBCodeTextObject, getTextColor, getTextStyleOptions } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import { fixedInt, rgbHexToRgba } from "#utils/common"; import { argbFromRgba } from "@material/material-color-utilities"; diff --git a/src/ui/handlers/achvs-ui-handler.ts b/src/ui/handlers/achvs-ui-handler.ts index f8f73dd2078..dea1829499e 100644 --- a/src/ui/handlers/achvs-ui-handler.ts +++ b/src/ui/handlers/achvs-ui-handler.ts @@ -5,11 +5,11 @@ import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; import type { Achv } from "#system/achv"; import { achvs, getAchievementDescription } from "#system/achv"; -import type { AchvUnlocks, VoucherUnlocks } from "#system/game-data"; import type { Voucher } from "#system/voucher"; import { getVoucherTypeIcon, getVoucherTypeName, vouchers } from "#system/voucher"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import type { AchvUnlocks, VoucherUnlocks } from "#types/save-data"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { ScrollBar } from "#ui/scroll-bar"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; diff --git a/src/ui/handlers/admin-ui-handler.ts b/src/ui/handlers/admin-ui-handler.ts index 9ca30e35313..38420c61010 100644 --- a/src/ui/handlers/admin-ui-handler.ts +++ b/src/ui/handlers/admin-ui-handler.ts @@ -3,9 +3,9 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import { getTextColor } from "#ui/text"; import { toTitleCase } from "#utils/strings"; diff --git a/src/ui/handlers/autocomplete-ui-handler.ts b/src/ui/handlers/autocomplete-ui-handler.ts index 914fe23a123..337b17048dc 100644 --- a/src/ui/handlers/autocomplete-ui-handler.ts +++ b/src/ui/handlers/autocomplete-ui-handler.ts @@ -1,6 +1,6 @@ import { Button } from "#enums/buttons"; import { UiMode } from "#enums/ui-mode"; -import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler"; +import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler"; export class AutoCompleteUiHandler extends AbstractOptionSelectUiHandler { modalContainer: Phaser.GameObjects.Container; diff --git a/src/ui/handlers/awaitable-ui-handler.ts b/src/ui/handlers/awaitable-ui-handler.ts index 9dcd3377da2..e8513b4acc1 100644 --- a/src/ui/handlers/awaitable-ui-handler.ts +++ b/src/ui/handlers/awaitable-ui-handler.ts @@ -1,7 +1,7 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import type { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { UiHandler } from "#ui/ui-handler"; export abstract class AwaitableUiHandler extends UiHandler { protected awaitingActionInput: boolean; diff --git a/src/ui/handlers/ball-ui-handler.ts b/src/ui/handlers/ball-ui-handler.ts index 3d1868c207e..3d8efca96b8 100644 --- a/src/ui/handlers/ball-ui-handler.ts +++ b/src/ui/handlers/ball-ui-handler.ts @@ -5,8 +5,8 @@ import { Command } from "#enums/command"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; import type { CommandPhase } from "#phases/command-phase"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addTextObject, getTextStyleOptions } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; diff --git a/src/ui/handlers/battle-message-ui-handler.ts b/src/ui/handlers/battle-message-ui-handler.ts index 6912109c7e7..f845f22a730 100644 --- a/src/ui/handlers/battle-message-ui-handler.ts +++ b/src/ui/handlers/battle-message-ui-handler.ts @@ -3,7 +3,7 @@ import { Button } from "#enums/buttons"; import { getStatKey, PERMANENT_STATS } from "#enums/stat"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; diff --git a/src/ui/handlers/challenges-select-ui-handler.ts b/src/ui/handlers/challenges-select-ui-handler.ts index 5cc91285a74..62f9d578667 100644 --- a/src/ui/handlers/challenges-select-ui-handler.ts +++ b/src/ui/handlers/challenges-select-ui-handler.ts @@ -5,8 +5,8 @@ import { Challenges } from "#enums/challenges"; import { Color, ShadowColor } from "#enums/color"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addTextObject } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import { getLocalizedSpriteKey } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/change-password-form-ui-handler.ts b/src/ui/handlers/change-password-form-ui-handler.ts index f4fdf349978..eccc67ffb04 100644 --- a/src/ui/handlers/change-password-form-ui-handler.ts +++ b/src/ui/handlers/change-password-form-ui-handler.ts @@ -1,9 +1,9 @@ import { globalScene } from "#app/global-scene"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { UiMode } from "#enums/ui-mode"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import i18next from "i18next"; export class ChangePasswordFormUiHandler extends FormModalUiHandler { diff --git a/src/ui/handlers/command-ui-handler.ts b/src/ui/handlers/command-ui-handler.ts index de5e51a4210..693fe0eefef 100644 --- a/src/ui/handlers/command-ui-handler.ts +++ b/src/ui/handlers/command-ui-handler.ts @@ -9,9 +9,9 @@ import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; import { TerastallizeAccessModifier } from "#modifiers/modifier"; import type { CommandPhase } from "#phases/command-phase"; -import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import { addTextObject } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import i18next from "i18next"; export class CommandUiHandler extends UiHandler { diff --git a/src/ui/handlers/confirm-ui-handler.ts b/src/ui/handlers/confirm-ui-handler.ts index 77f1f182514..64a0bb7028a 100644 --- a/src/ui/handlers/confirm-ui-handler.ts +++ b/src/ui/handlers/confirm-ui-handler.ts @@ -1,8 +1,8 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { UiMode } from "#enums/ui-mode"; -import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler"; -import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler"; +import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler"; +import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler"; import i18next from "i18next"; export class ConfirmUiHandler extends AbstractOptionSelectUiHandler { diff --git a/src/ui/handlers/egg-gacha-ui-handler.ts b/src/ui/handlers/egg-gacha-ui-handler.ts index bd96b4d9392..f24c8c04fdb 100644 --- a/src/ui/handlers/egg-gacha-ui-handler.ts +++ b/src/ui/handlers/egg-gacha-ui-handler.ts @@ -9,7 +9,7 @@ import { GachaType } from "#enums/gacha-types"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; import { getVoucherTypeIcon, VoucherType } from "#system/voucher"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; import { addTextObject, getEggTierTextTint, getTextStyleOptions } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { fixedInt, randSeedShuffle } from "#utils/common"; @@ -96,7 +96,7 @@ export class EggGachaUiHandler extends MessageUiHandler { legendaryLabelY = 0; } - const gachaUpLabel = addTextObject(gachaX, gachaY, i18next.t("egg:legendaryUPGacha"), gachaTextStyle).setOrigin(0); + const gachaUpLabel = addTextObject(gachaX, gachaY, i18next.t("egg:legendaryUpGacha"), gachaTextStyle).setOrigin(0); gachaInfoContainer.add(gachaUpLabel); switch (gachaType as GachaType) { @@ -124,14 +124,14 @@ export class EggGachaUiHandler extends MessageUiHandler { gachaUpLabel.setAlign("center").setY(0); } - gachaUpLabel.setText(i18next.t("egg:moveUPGacha")).setX(0).setOrigin(0.5, 0); + gachaUpLabel.setText(i18next.t("egg:moveUpGacha")).setX(0).setOrigin(0.5, 0); break; case GachaType.SHINY: if (["de", "fr", "ko", "ru"].includes(currentLanguage)) { gachaUpLabel.setAlign("center").setY(0); } - gachaUpLabel.setText(i18next.t("egg:shinyUPGacha")).setX(0).setOrigin(0.5, 0); + gachaUpLabel.setText(i18next.t("egg:shinyUpGacha")).setX(0).setOrigin(0.5, 0); break; } diff --git a/src/ui/handlers/egg-hatch-scene-handler.ts b/src/ui/handlers/egg-hatch-scene-ui-handler.ts similarity index 93% rename from src/ui/handlers/egg-hatch-scene-handler.ts rename to src/ui/handlers/egg-hatch-scene-ui-handler.ts index b7b5b78641f..d0827532e14 100644 --- a/src/ui/handlers/egg-hatch-scene-handler.ts +++ b/src/ui/handlers/egg-hatch-scene-ui-handler.ts @@ -1,9 +1,9 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { UiHandler } from "#ui/ui-handler"; -export class EggHatchSceneHandler extends UiHandler { +export class EggHatchSceneUiHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; /** diff --git a/src/ui/handlers/egg-list-ui-handler.ts b/src/ui/handlers/egg-list-ui-handler.ts index 2161073e6b1..3ec509261bb 100644 --- a/src/ui/handlers/egg-list-ui-handler.ts +++ b/src/ui/handlers/egg-list-ui-handler.ts @@ -2,10 +2,10 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; -import { ScrollableGridUiHandler } from "#ui/handlers/scrollable-grid-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { PokemonIconAnimHelper, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; +import { ScrollBar } from "#ui/scroll-bar"; +import { ScrollableGridHelper } from "#ui/scrollable-grid-helper"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; @@ -25,9 +25,9 @@ export class EggListUiHandler extends MessageUiHandler { private eggListMessageBoxContainer: Phaser.GameObjects.Container; private cursorObj: Phaser.GameObjects.Image; - private scrollGridHandler: ScrollableGridUiHandler; + private scrollGridHandler: ScrollableGridHelper; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; constructor() { super(UiMode.EGG_LIST); @@ -45,7 +45,7 @@ export class EggListUiHandler extends MessageUiHandler { const eggListBg = globalScene.add.image(0, 0, "egg_list_bg").setOrigin(0); - this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler = new PokemonIconAnimHelper(); this.iconAnimHandler.setup(); this.eggNameText = addTextObject(8, 68, "", TextStyle.SUMMARY).setOrigin(0); @@ -64,7 +64,7 @@ export class EggListUiHandler extends MessageUiHandler { const scrollBar = new ScrollBar(310, 5, 4, 170, this.ROWS); - this.scrollGridHandler = new ScrollableGridUiHandler(this, this.ROWS, this.COLUMNS) + this.scrollGridHandler = new ScrollableGridHelper(this, this.ROWS, this.COLUMNS) .withScrollBar(scrollBar) .withUpdateGridCallBack(() => this.updateEggIcons()) .withUpdateSingleElementCallback((i: number) => this.setEggDetails(i)); diff --git a/src/ui/handlers/egg-summary-ui-handler.ts b/src/ui/handlers/egg-summary-ui-handler.ts index 046f3b80ea4..35dc9c5176f 100644 --- a/src/ui/handlers/egg-summary-ui-handler.ts +++ b/src/ui/handlers/egg-summary-ui-handler.ts @@ -3,12 +3,12 @@ import { getEggTierForSpecies } from "#data/egg"; import type { EggHatchData } from "#data/egg-hatch-data"; import { Button } from "#enums/buttons"; import { UiMode } from "#enums/ui-mode"; -import { HatchedPokemonContainer } from "#ui/containers/hatched-pokemon-container"; -import { PokemonHatchInfoContainer } from "#ui/containers/pokemon-hatch-info-container"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; -import { ScrollableGridUiHandler } from "#ui/handlers/scrollable-grid-handler"; +import { HatchedPokemonContainer } from "#ui/hatched-pokemon-container"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { PokemonHatchInfoContainer } from "#ui/pokemon-hatch-info-container"; +import { PokemonIconAnimHelper, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; +import { ScrollBar } from "#ui/scroll-bar"; +import { ScrollableGridHelper } from "#ui/scrollable-grid-helper"; const iconContainerX = 112; const iconContainerY = 9; @@ -34,11 +34,11 @@ export class EggSummaryUiHandler extends MessageUiHandler { /** hatch info container that displays the current pokemon / hatch (main element on left hand side) */ private infoContainer: PokemonHatchInfoContainer; /** handles jumping animations for the pokemon sprite icons */ - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; private eggHatchBg: Phaser.GameObjects.Image; private eggHatchData: EggHatchData[]; - private scrollGridHandler: ScrollableGridUiHandler; + private scrollGridHandler: ScrollableGridHelper; private cursorObj: Phaser.GameObjects.Image; /** used to add a delay before which it is not possible to exit the summary */ @@ -67,7 +67,7 @@ export class EggSummaryUiHandler extends MessageUiHandler { this.eggHatchContainer.setVisible(false); ui.add(this.eggHatchContainer); - this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler = new PokemonIconAnimHelper(); this.iconAnimHandler.setup(); this.eggHatchBg = globalScene.add.image(0, 0, "egg_summary_bg"); @@ -97,7 +97,7 @@ export class EggSummaryUiHandler extends MessageUiHandler { ); this.summaryContainer.add(scrollBar); - this.scrollGridHandler = new ScrollableGridUiHandler(this, numRows, numCols) + this.scrollGridHandler = new ScrollableGridHelper(this, numRows, numCols) .withScrollBar(scrollBar) .withUpdateGridCallBack(() => this.updatePokemonIcons()) .withUpdateSingleElementCallback((i: number) => this.infoContainer.showHatchInfo(this.eggHatchData[i])); diff --git a/src/ui/handlers/evolution-scene-handler.ts b/src/ui/handlers/evolution-scene-ui-handler.ts similarity index 94% rename from src/ui/handlers/evolution-scene-handler.ts rename to src/ui/handlers/evolution-scene-ui-handler.ts index 55405d8f437..ba3d8f8f57f 100644 --- a/src/ui/handlers/evolution-scene-handler.ts +++ b/src/ui/handlers/evolution-scene-ui-handler.ts @@ -2,10 +2,10 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; import { addTextObject } from "#ui/text"; -export class EvolutionSceneHandler extends MessageUiHandler { +export class EvolutionSceneUiHandler extends MessageUiHandler { public evolutionContainer: Phaser.GameObjects.Container; public messageBg: Phaser.GameObjects.Image; public messageContainer: Phaser.GameObjects.Container; diff --git a/src/ui/handlers/fight-ui-handler.ts b/src/ui/handlers/fight-ui-handler.ts index 9dd00a90b66..72b6949eb9c 100644 --- a/src/ui/handlers/fight-ui-handler.ts +++ b/src/ui/handlers/fight-ui-handler.ts @@ -12,9 +12,9 @@ import { UiMode } from "#enums/ui-mode"; import type { EnemyPokemon, Pokemon } from "#field/pokemon"; import type { PokemonMove } from "#moves/pokemon-move"; import type { CommandPhase } from "#phases/command-phase"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; import { addTextObject, getTextColor } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { fixedInt, getLocalizedSpriteKey, padInt } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/form-modal-ui-handler.ts b/src/ui/handlers/form-modal-ui-handler.ts index af1d8653df7..2efd39ca359 100644 --- a/src/ui/handlers/form-modal-ui-handler.ts +++ b/src/ui/handlers/form-modal-ui-handler.ts @@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene"; import { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; -import { ModalUiHandler } from "#ui/handlers/modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; +import { ModalUiHandler } from "#ui/modal-ui-handler"; import { addTextInputObject, addTextObject, getTextColor } from "#ui/text"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import { fixedInt } from "#utils/common"; diff --git a/src/ui/handlers/game-stats-ui-handler.ts b/src/ui/handlers/game-stats-ui-handler.ts index 9ffb7346b4d..24ff842a902 100644 --- a/src/ui/handlers/game-stats-ui-handler.ts +++ b/src/ui/handlers/game-stats-ui-handler.ts @@ -7,8 +7,8 @@ import { PlayerGender } from "#enums/player-gender"; import { TextStyle } from "#enums/text-style"; import { UiTheme } from "#enums/ui-theme"; import type { GameData } from "#system/game-data"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addTextObject } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import { formatFancyLargeNumber, getPlayTimeString } from "#utils/common"; import { toTitleCase } from "#utils/strings"; @@ -108,7 +108,7 @@ const displayStats: DisplayStats = { sourceFunc: gameData => gameData.gameStats.highestDamage.toString(), }, highestHeal: { - label_key: "highestHPHealed", + label_key: "highestHpHealed", sourceFunc: gameData => gameData.gameStats.highestHeal.toString(), }, pokemonSeen: { diff --git a/src/ui/handlers/loading-modal-ui-handler.ts b/src/ui/handlers/loading-modal-ui-handler.ts index 9b401e17f91..de00d911c47 100644 --- a/src/ui/handlers/loading-modal-ui-handler.ts +++ b/src/ui/handlers/loading-modal-ui-handler.ts @@ -1,6 +1,6 @@ import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import { ModalUiHandler } from "#ui/handlers/modal-ui-handler"; +import { ModalUiHandler } from "#ui/modal-ui-handler"; import { addTextObject } from "#ui/text"; import i18next from "i18next"; diff --git a/src/ui/handlers/login-form-ui-handler.ts b/src/ui/handlers/login-form-ui-handler.ts index aeebd23ce43..44c5b93131f 100644 --- a/src/ui/handlers/login-form-ui-handler.ts +++ b/src/ui/handlers/login-form-ui-handler.ts @@ -2,10 +2,11 @@ import { pokerogueApi } from "#api/pokerogue-api"; import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import { languageOptions } from "#system/settings-language"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { fixedInt } from "#utils/common"; @@ -31,6 +32,7 @@ export class LoginFormUiHandler extends FormModalUiHandler { private discordImage: Phaser.GameObjects.Image; private usernameInfoImage: Phaser.GameObjects.Image; private saveDownloadImage: Phaser.GameObjects.Image; + private changeLanguageImage: Phaser.GameObjects.Image; private externalPartyContainer: Phaser.GameObjects.Container; private infoContainer: Phaser.GameObjects.Container; private externalPartyBg: Phaser.GameObjects.NineSlice; @@ -82,8 +84,14 @@ export class LoginFormUiHandler extends FormModalUiHandler { scale: 0.75, }); + this.changeLanguageImage = this.buildInteractableImage("language_icon", "change-language-icon", { + x: 40, + scale: 0.5, + }); + this.infoContainer.add(this.usernameInfoImage); this.infoContainer.add(this.saveDownloadImage); + this.infoContainer.add(this.changeLanguageImage); this.getUi().add(this.infoContainer); this.infoContainer.setVisible(false); this.infoContainer.disableInteractive(); @@ -163,13 +171,18 @@ export class LoginFormUiHandler extends FormModalUiHandler { const [usernameInput, passwordInput] = this.inputs; - pokerogueApi.account.login({ username: usernameInput.text, password: passwordInput.text }).then(error => { - if (!error && originalLoginAction) { - originalLoginAction(); - } else { - onFail(error); - } - }); + pokerogueApi.account + .login({ + username: usernameInput.text, + password: passwordInput.text, + }) + .then(error => { + if (!error && originalLoginAction) { + originalLoginAction(); + } else { + onFail(error); + } + }); } }; @@ -185,9 +198,13 @@ export class LoginFormUiHandler extends FormModalUiHandler { this.infoContainer.setVisible(false); this.setMouseCursorStyle("default"); //reset cursor - [this.discordImage, this.googleImage, this.usernameInfoImage, this.saveDownloadImage].forEach(img => - img.off("pointerdown"), - ); + [ + this.discordImage, + this.googleImage, + this.usernameInfoImage, + this.saveDownloadImage, + this.changeLanguageImage, + ].forEach(img => img.off("pointerdown")); } private processExternalProvider(config: ModalConfig): void { @@ -206,6 +223,7 @@ export class LoginFormUiHandler extends FormModalUiHandler { this.getUi().moveTo(this.infoContainer, this.getUi().length - 1); this.usernameInfoImage.setPositionRelative(this.infoContainer, 0, 0); this.saveDownloadImage.setPositionRelative(this.infoContainer, 20, 0); + this.changeLanguageImage.setPositionRelative(this.infoContainer, 40, 0); this.discordImage.on("pointerdown", () => { const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); @@ -288,6 +306,14 @@ export class LoginFormUiHandler extends FormModalUiHandler { } }); + this.changeLanguageImage.on("pointerdown", () => { + globalScene.ui.setOverlayMode(UiMode.OPTION_SELECT, { + options: languageOptions, + maxOptions: 7, + delay: 1000, + }); + }); + this.externalPartyContainer.setAlpha(0); globalScene.tweens.add({ targets: this.externalPartyContainer, diff --git a/src/ui/handlers/menu-ui-handler.ts b/src/ui/handlers/menu-ui-handler.ts index df1908bae39..419f2489818 100644 --- a/src/ui/handlers/menu-ui-handler.ts +++ b/src/ui/handlers/menu-ui-handler.ts @@ -7,10 +7,10 @@ import { Button } from "#enums/buttons"; import { GameDataType } from "#enums/game-data-type"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { BgmBar } from "#ui/containers/bgm-bar"; -import type { OptionSelectConfig, OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import type { OptionSelectConfig, OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; +import { BgmBar } from "#ui/bgm-bar"; +import { MessageUiHandler } from "#ui/message-ui-handler"; import { addTextObject, getTextStyleOptions } from "#ui/text"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import { fixedInt, isLocal, sessionIdKey } from "#utils/common"; diff --git a/src/ui/handlers/message-ui-handler.ts b/src/ui/handlers/message-ui-handler.ts index b8e3f983cca..1deaca78493 100644 --- a/src/ui/handlers/message-ui-handler.ts +++ b/src/ui/handlers/message-ui-handler.ts @@ -1,6 +1,6 @@ import { globalScene } from "#app/global-scene"; import type { UiMode } from "#enums/ui-mode"; -import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; +import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; import { getFrameMs } from "#utils/common"; export abstract class MessageUiHandler extends AwaitableUiHandler { diff --git a/src/ui/handlers/modal-ui-handler.ts b/src/ui/handlers/modal-ui-handler.ts index e6eecece9a2..c145363b244 100644 --- a/src/ui/handlers/modal-ui-handler.ts +++ b/src/ui/handlers/modal-ui-handler.ts @@ -2,8 +2,8 @@ import { globalScene } from "#app/global-scene"; import type { Button } from "#enums/buttons"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addTextObject } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow, WindowVariant } from "#ui/ui-theme"; export interface ModalConfig { diff --git a/src/ui/handlers/modifier-select-ui-handler.ts b/src/ui/handlers/modifier-select-ui-handler.ts index a721bf9e7db..95bc30fb97c 100644 --- a/src/ui/handlers/modifier-select-ui-handler.ts +++ b/src/ui/handlers/modifier-select-ui-handler.ts @@ -11,8 +11,8 @@ import { UiMode } from "#enums/ui-mode"; import { HealShopCostModifier, LockModifierTiersModifier, PokemonHeldItemModifier } from "#modifiers/modifier"; import type { ModifierTypeOption } from "#modifiers/modifier-type"; import { getPlayerShopModifierTypeOptionsForWave, TmModifierType } from "#modifiers/modifier-type"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; +import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; import { addTextObject, getModifierTierTextTint, getTextColor, getTextStyleOptions } from "#ui/text"; import { formatMoney, NumberHolder } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/mystery-encounter-ui-handler.ts b/src/ui/handlers/mystery-encounter-ui-handler.ts index 9bc6f0681ee..bbbd3cb4af8 100644 --- a/src/ui/handlers/mystery-encounter-ui-handler.ts +++ b/src/ui/handlers/mystery-encounter-ui-handler.ts @@ -9,9 +9,9 @@ import { getEncounterText } from "#mystery-encounters/encounter-dialogue-utils"; import type { OptionSelectSettings } from "#mystery-encounters/encounter-phase-utils"; import type { MysteryEncounterOption } from "#mystery-encounters/mystery-encounter-option"; import type { MysteryEncounterPhase } from "#phases/mystery-encounter-phases"; -import { PartyUiMode } from "#ui/handlers/party-ui-handler"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { PartyUiMode } from "#ui/party-ui-handler"; import { addBBCodeTextObject, getBBCodeFrag } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow, WindowVariant } from "#ui/ui-theme"; import { fixedInt, isNullOrUndefined } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/party-ui-handler.ts b/src/ui/handlers/party-ui-handler.ts index ef5ed099153..d4014cc0288 100644 --- a/src/ui/handlers/party-ui-handler.ts +++ b/src/ui/handlers/party-ui-handler.ts @@ -21,9 +21,9 @@ import type { PokemonMove } from "#moves/pokemon-move"; import type { CommandPhase } from "#phases/command-phase"; import { getVariantTint } from "#sprites/variant"; import type { TurnMove } from "#types/turn-move"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; +import { PokemonIconAnimHelper, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { applyChallenges } from "#utils/challenge-utils"; @@ -201,7 +201,7 @@ export class PartyUiHandler extends MessageUiHandler { private tmMoveId: MoveId; private showMovePp: boolean; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; private blockInput: boolean; @@ -320,7 +320,7 @@ export class PartyUiHandler extends MessageUiHandler { this.optionsContainer = globalScene.add.container(globalScene.scaledCanvas.width - 1, -1); partyContainer.add(this.optionsContainer); - this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler = new PokemonIconAnimHelper(); this.iconAnimHandler.setup(); const partyDiscardModeButton = new PartyDiscardModeButton(DISCARD_BUTTON_X, DISCARD_BUTTON_Y, this); @@ -1892,12 +1892,12 @@ class PartySlot extends Phaser.GameObjects.Container { private slotBgKey: string; private pokemonIcon: Phaser.GameObjects.Container; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; constructor( slotIndex: number, pokemon: PlayerPokemon, - iconAnimHandler: PokemonIconAnimHandler, + iconAnimHandler: PokemonIconAnimHelper, partyUiMode: PartyUiMode, tmMoveId: MoveId, ) { diff --git a/src/ui/containers/pokedex-page-ui-handler.ts b/src/ui/handlers/pokedex-page-ui-handler.ts similarity index 99% rename from src/ui/containers/pokedex-page-ui-handler.ts rename to src/ui/handlers/pokedex-page-ui-handler.ts index ef1c1a6896c..253309bf94a 100644 --- a/src/ui/containers/pokedex-page-ui-handler.ts +++ b/src/ui/handlers/pokedex-page-ui-handler.ts @@ -43,15 +43,15 @@ import { TimeOfDay } from "#enums/time-of-day"; import { UiMode } from "#enums/ui-mode"; import type { Variant } from "#sprites/variant"; import { getVariantIcon, getVariantTint } from "#sprites/variant"; -import type { StarterAttributes } from "#system/game-data"; import { SettingKeyboard } from "#system/settings-keyboard"; import type { DexEntry } from "#types/dex-data"; -import { BaseStatsOverlay } from "#ui/containers/base-stats-overlay"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import { PokedexInfoOverlay } from "#ui/containers/pokedex-info-overlay"; -import { StatsContainer } from "#ui/containers/stats-container"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import type { StarterAttributes } from "#types/save-data"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import { BaseStatsOverlay } from "#ui/base-stats-overlay"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; +import { PokedexInfoOverlay } from "#ui/pokedex-info-overlay"; +import { StatsContainer } from "#ui/stats-container"; import { addBBCodeTextObject, addTextObject, getTextColor, getTextStyleOptions } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { BooleanHolder, getLocalizedSpriteKey, isNullOrUndefined, padInt, rgbHexToRgba } from "#utils/common"; diff --git a/src/ui/handlers/pokedex-scan-ui-handler.ts b/src/ui/handlers/pokedex-scan-ui-handler.ts index bb3cec5bb56..1f5195588f3 100644 --- a/src/ui/handlers/pokedex-scan-ui-handler.ts +++ b/src/ui/handlers/pokedex-scan-ui-handler.ts @@ -1,11 +1,11 @@ import { allAbilities, allMoves, allSpecies } from "#data/data-lists"; import { UiMode } from "#enums/ui-mode"; import type { PlayerPokemon } from "#field/pokemon"; -import { FilterTextRow } from "#ui/containers/filter-text"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import { FilterTextRow } from "#ui/filter-text"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import { isNullOrUndefined } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/pokedex-ui-handler.ts b/src/ui/handlers/pokedex-ui-handler.ts index 3500fa97436..c6f9dbee448 100644 --- a/src/ui/handlers/pokedex-ui-handler.ts +++ b/src/ui/handlers/pokedex-ui-handler.ts @@ -31,24 +31,17 @@ import { UiMode } from "#enums/ui-mode"; import { UiTheme } from "#enums/ui-theme"; import type { Variant } from "#sprites/variant"; import { getVariantIcon, getVariantTint } from "#sprites/variant"; -import type { DexAttrProps, StarterAttributes } from "#system/game-data"; import { SettingKeyboard } from "#system/settings-keyboard"; import type { DexEntry } from "#types/dex-data"; -import { - DropDown, - DropDownLabel, - DropDownOption, - DropDownState, - DropDownType, - SortCriteria, -} from "#ui/containers/dropdown"; -import { FilterBar } from "#ui/containers/filter-bar"; -import { FilterText, FilterTextRow } from "#ui/containers/filter-text"; -import { PokedexMonContainer } from "#ui/containers/pokedex-mon-container"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; +import type { DexAttrProps, StarterAttributes } from "#types/save-data"; +import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler"; +import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown"; +import { FilterBar } from "#ui/filter-bar"; +import { FilterText, FilterTextRow } from "#ui/filter-text"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { PokedexMonContainer } from "#ui/pokedex-mon-container"; +import { PokemonIconAnimHelper, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; +import { ScrollBar } from "#ui/scroll-bar"; import { addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { BooleanHolder, fixedInt, getLocalizedSpriteKey, padInt, randIntRange, rgbHexToRgba } from "#utils/common"; @@ -198,7 +191,7 @@ export class PokedexUiHandler extends MessageUiHandler { public cursorObj: Phaser.GameObjects.Image; private pokerusCursorObjs: Phaser.GameObjects.Image[]; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; private starterPreferences: StarterPreferences; @@ -482,7 +475,7 @@ export class PokedexUiHandler extends MessageUiHandler { pokemonContainerWindow.setVisible(false); } - this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler = new PokemonIconAnimHelper(); this.iconAnimHandler.setup(); this.pokemonNumberText = addTextObject(6, 141, "", TextStyle.SUMMARY); diff --git a/src/ui/handlers/registration-form-ui-handler.ts b/src/ui/handlers/registration-form-ui-handler.ts index d424e44b455..2c8080d534d 100644 --- a/src/ui/handlers/registration-form-ui-handler.ts +++ b/src/ui/handlers/registration-form-ui-handler.ts @@ -2,9 +2,9 @@ import { pokerogueApi } from "#api/pokerogue-api"; import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import { addTextObject } from "#ui/text"; import i18next from "i18next"; diff --git a/src/ui/handlers/rename-form-ui-handler.ts b/src/ui/handlers/rename-form-ui-handler.ts index f1d9ae3c981..9da5b0e8554 100644 --- a/src/ui/handlers/rename-form-ui-handler.ts +++ b/src/ui/handlers/rename-form-ui-handler.ts @@ -1,7 +1,7 @@ import type { PlayerPokemon } from "#field/pokemon"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import i18next from "i18next"; export class RenameFormUiHandler extends FormModalUiHandler { diff --git a/src/ui/handlers/run-history-ui-handler.ts b/src/ui/handlers/run-history-ui-handler.ts index cec2b95cdd5..4dd73d4826b 100644 --- a/src/ui/handlers/run-history-ui-handler.ts +++ b/src/ui/handlers/run-history-ui-handler.ts @@ -6,10 +6,10 @@ import { PlayerGender } from "#enums/player-gender"; import { TextStyle } from "#enums/text-style"; import { TrainerVariant } from "#enums/trainer-variant"; import { UiMode } from "#enums/ui-mode"; -import type { RunEntry } from "#system/game-data"; import type { PokemonData } from "#system/pokemon-data"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { RunDisplayMode } from "#ui/handlers/run-info-ui-handler"; +import type { RunEntry } from "#types/save-data"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { RunDisplayMode } from "#ui/run-info-ui-handler"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { fixedInt, formatLargeNumber } from "#utils/common"; diff --git a/src/ui/handlers/run-info-ui-handler.ts b/src/ui/handlers/run-info-ui-handler.ts index 3693a58bf48..556884194b1 100644 --- a/src/ui/handlers/run-info-ui-handler.ts +++ b/src/ui/handlers/run-info-ui-handler.ts @@ -19,11 +19,11 @@ import { UiMode } from "#enums/ui-mode"; import * as Modifier from "#modifiers/modifier"; import { getLuckString, getLuckTextTint } from "#modifiers/modifier-type"; import { getVariantTint } from "#sprites/variant"; -import type { SessionSaveData } from "#system/game-data"; import type { PokemonData } from "#system/pokemon-data"; import { SettingKeyboard } from "#system/settings-keyboard"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import type { SessionSaveData } from "#types/save-data"; import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import { formatFancyLargeNumber, formatLargeNumber, formatMoney, getPlayTimeString } from "#utils/common"; import { toCamelCase } from "#utils/strings"; @@ -685,7 +685,7 @@ export class RunInfoUiHandler extends UiHandler { /** * This function parses the Challenges section of the Run Entry and returns a list of active challenge. - * @return string[] of active challenge names + * @returns string[] of active challenge names */ private challengeParser(): string[] { const rules: string[] = []; diff --git a/src/ui/handlers/save-slot-select-ui-handler.ts b/src/ui/handlers/save-slot-select-ui-handler.ts index 1b062e964be..a71be5dd070 100644 --- a/src/ui/handlers/save-slot-select-ui-handler.ts +++ b/src/ui/handlers/save-slot-select-ui-handler.ts @@ -6,11 +6,11 @@ import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; // biome-ignore lint/performance/noNamespaceImport: See `src/system/game-data.ts` import * as Modifier from "#modifiers/modifier"; -import type { SessionSaveData } from "#system/game-data"; import type { PokemonData } from "#system/pokemon-data"; -import type { OptionSelectConfig } from "#ui/handlers/abstract-option-select-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { RunDisplayMode } from "#ui/handlers/run-info-ui-handler"; +import type { SessionSaveData } from "#types/save-data"; +import type { OptionSelectConfig } from "#ui/abstract-option-select-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { RunDisplayMode } from "#ui/run-info-ui-handler"; import { addTextObject } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { fixedInt, formatLargeNumber, getPlayTimeString, isNullOrUndefined } from "#utils/common"; diff --git a/src/ui/handlers/session-reload-modal-ui-handler.ts b/src/ui/handlers/session-reload-modal-ui-handler.ts index 33c18b1974a..1f5a205f990 100644 --- a/src/ui/handlers/session-reload-modal-ui-handler.ts +++ b/src/ui/handlers/session-reload-modal-ui-handler.ts @@ -1,7 +1,7 @@ import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; -import { ModalUiHandler } from "#ui/handlers/modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; +import { ModalUiHandler } from "#ui/modal-ui-handler"; import { addTextObject } from "#ui/text"; export class SessionReloadModalUiHandler extends ModalUiHandler { diff --git a/src/ui/handlers/starter-select-ui-handler.ts b/src/ui/handlers/starter-select-ui-handler.ts index 60d8a4dc4d6..18be7e130e3 100644 --- a/src/ui/handlers/starter-select-ui-handler.ts +++ b/src/ui/handlers/starter-select-ui-handler.ts @@ -46,26 +46,19 @@ import { BattleSceneEventType } from "#events/battle-scene"; import type { Variant } from "#sprites/variant"; import { getVariantIcon, getVariantTint } from "#sprites/variant"; import { achvs } from "#system/achv"; -import type { DexAttrProps, StarterAttributes, StarterDataEntry, StarterMoveset } from "#system/game-data"; import { RibbonData } from "#system/ribbons/ribbon-data"; import { SettingKeyboard } from "#system/settings-keyboard"; import type { DexEntry } from "#types/dex-data"; -import { - DropDown, - DropDownLabel, - DropDownOption, - DropDownState, - DropDownType, - SortCriteria, -} from "#ui/containers/dropdown"; -import { FilterBar } from "#ui/containers/filter-bar"; -import { MoveInfoOverlay } from "#ui/containers/move-info-overlay"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { StarterContainer } from "#ui/containers/starter-container"; -import { StatsContainer } from "#ui/containers/stats-container"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { PokemonIconAnimHandler, PokemonIconAnimMode } from "#ui/handlers/pokemon-icon-anim-handler"; +import type { DexAttrProps, StarterAttributes, StarterDataEntry, StarterMoveset } from "#types/save-data"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import { DropDown, DropDownLabel, DropDownOption, DropDownState, DropDownType, SortCriteria } from "#ui/dropdown"; +import { FilterBar } from "#ui/filter-bar"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { MoveInfoOverlay } from "#ui/move-info-overlay"; +import { PokemonIconAnimHelper, PokemonIconAnimMode } from "#ui/pokemon-icon-anim-helper"; +import { ScrollBar } from "#ui/scroll-bar"; +import { StarterContainer } from "#ui/starter-container"; +import { StatsContainer } from "#ui/stats-container"; import { addBBCodeTextObject, addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import { applyChallenges, checkStarterValidForChallenge } from "#utils/challenge-utils"; @@ -398,7 +391,7 @@ export class StarterSelectUiHandler extends MessageUiHandler { private startCursorObj: Phaser.GameObjects.NineSlice; private randomCursorObj: Phaser.GameObjects.NineSlice; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHelper; //variables to keep track of the dynamically rendered list of instruction prompts for starter select private instructionRowX = 0; @@ -611,7 +604,7 @@ export class StarterSelectUiHandler extends MessageUiHandler { starterContainerWindow.setVisible(false); } - this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler = new PokemonIconAnimHelper(); this.iconAnimHandler.setup(); this.pokemonSprite = globalScene.add.sprite(53, 63, "pkmn__sub"); diff --git a/src/ui/handlers/summary-ui-handler.ts b/src/ui/handlers/summary-ui-handler.ts index e73c5bae431..1c647573cbf 100644 --- a/src/ui/handlers/summary-ui-handler.ts +++ b/src/ui/handlers/summary-ui-handler.ts @@ -25,8 +25,8 @@ import type { PokemonMove } from "#moves/pokemon-move"; import type { Variant } from "#sprites/variant"; import { getVariantTint } from "#sprites/variant"; import { achvs } from "#system/achv"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { fixedInt, formatStat, diff --git a/src/ui/handlers/target-select-ui-handler.ts b/src/ui/handlers/target-select-ui-handler.ts index 777a6734383..4e3096b96f4 100644 --- a/src/ui/handlers/target-select-ui-handler.ts +++ b/src/ui/handlers/target-select-ui-handler.ts @@ -7,7 +7,7 @@ import { UiMode } from "#enums/ui-mode"; import type { Pokemon } from "#field/pokemon"; import type { ModifierBar } from "#modifiers/modifier"; import { getMoveTargets } from "#moves/move-utils"; -import { UiHandler } from "#ui/handlers/ui-handler"; +import { UiHandler } from "#ui/ui-handler"; import { fixedInt, isNullOrUndefined } from "#utils/common"; export type TargetSelectCallback = (targets: BattlerIndex[]) => void; diff --git a/src/ui/handlers/test-dialogue-ui-handler.ts b/src/ui/handlers/test-dialogue-ui-handler.ts index d72de64ef70..bd5c1a1dc37 100644 --- a/src/ui/handlers/test-dialogue-ui-handler.ts +++ b/src/ui/handlers/test-dialogue-ui-handler.ts @@ -1,9 +1,9 @@ import { UiMode } from "#enums/ui-mode"; import type { PlayerPokemon } from "#field/pokemon"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { InputFieldConfig } from "#ui/handlers/form-modal-ui-handler"; -import { FormModalUiHandler } from "#ui/handlers/form-modal-ui-handler"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; +import type { InputFieldConfig } from "#ui/form-modal-ui-handler"; +import { FormModalUiHandler } from "#ui/form-modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; import { isNullOrUndefined } from "#utils/common"; import i18next from "i18next"; diff --git a/src/ui/handlers/unavailable-modal-ui-handler.ts b/src/ui/handlers/unavailable-modal-ui-handler.ts index 5b885bfff77..7ba77dcac23 100644 --- a/src/ui/handlers/unavailable-modal-ui-handler.ts +++ b/src/ui/handlers/unavailable-modal-ui-handler.ts @@ -2,8 +2,8 @@ import { updateUserInfo } from "#app/account"; import { globalScene } from "#app/global-scene"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; -import type { ModalConfig } from "#ui/handlers/modal-ui-handler"; -import { ModalUiHandler } from "#ui/handlers/modal-ui-handler"; +import type { ModalConfig } from "#ui/modal-ui-handler"; +import { ModalUiHandler } from "#ui/modal-ui-handler"; import { addTextObject } from "#ui/text"; import { sessionIdKey } from "#utils/common"; import { removeCookie } from "#utils/cookies"; diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts index 2d9f3e6a6bd..17812785d1e 100644 --- a/src/ui/settings/abstract-control-settings-ui-handler.ts +++ b/src/ui/settings/abstract-control-settings-ui-handler.ts @@ -5,10 +5,10 @@ import type { Device } from "#enums/devices"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; import { getIconWithSettingName } from "#inputs/config-handler"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { UiHandler } from "#ui/handlers/ui-handler"; import { NavigationManager, NavigationMenu } from "#ui/navigation-menu"; +import { ScrollBar } from "#ui/scroll-bar"; import { addTextObject, getTextColor } from "#ui/text"; +import { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; import { toCamelCase } from "#utils/strings"; import i18next from "i18next"; diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index ef117fb6a34..e22c28116f5 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -4,10 +4,11 @@ import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; import type { SettingType } from "#system/settings"; import { Setting, SettingKeys } from "#system/settings"; +import type { AnyFn } from "#types/type-helpers"; import type { InputsIcons } from "#ui/abstract-control-settings-ui-handler"; -import { ScrollBar } from "#ui/containers/scroll-bar"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; import { NavigationManager, NavigationMenu } from "#ui/navigation-menu"; +import { ScrollBar } from "#ui/scroll-bar"; import { addTextObject, getTextColor } from "#ui/text"; import { addWindow } from "#ui/ui-theme"; import i18next from "i18next"; @@ -53,54 +54,47 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { */ setup() { const ui = this.getUi(); + const canvasWidth = globalScene.scaledCanvas.width; + const canvasHeight = globalScene.scaledCanvas.height; - this.settingsContainer = globalScene.add.container(1, -globalScene.scaledCanvas.height + 1); - this.settingsContainer.setName(`settings-${this.title}`); - this.settingsContainer.setInteractive( - new Phaser.Geom.Rectangle(0, 0, globalScene.scaledCanvas.width, globalScene.scaledCanvas.height - 20), - Phaser.Geom.Rectangle.Contains, - ); + this.settingsContainer = globalScene.add + .container(1, -canvasHeight + 1) + .setName(`settings-${this.title}`) + .setInteractive(new Phaser.Geom.Rectangle(0, 0, canvasWidth, canvasHeight - 20), Phaser.Geom.Rectangle.Contains); this.navigationIcons = {}; this.navigationContainer = new NavigationMenu(0, 0); + const navWidth = this.navigationContainer.width; + const navHeight = this.navigationContainer.height; - this.optionsBg = addWindow( - 0, - this.navigationContainer.height, - globalScene.scaledCanvas.width - 2, - globalScene.scaledCanvas.height - 16 - this.navigationContainer.height - 2, - ); - this.optionsBg.setName("window-options-bg"); - this.optionsBg.setOrigin(0, 0); + this.optionsBg = addWindow(0, navHeight, canvasWidth - 2, canvasHeight - 16 - navHeight - 2) + .setName("window-options-bg") + .setOrigin(0); - const actionsBg = addWindow( - 0, - globalScene.scaledCanvas.height - this.navigationContainer.height, - globalScene.scaledCanvas.width - 2, - 22, - ); - actionsBg.setOrigin(0, 0); + const actionsBg = addWindow(0, canvasHeight - navHeight, canvasWidth - 2, 22) // formatting + .setOrigin(0); - const iconAction = globalScene.add.sprite(0, 0, "keyboard"); - iconAction.setOrigin(0, -0.1); - iconAction.setPositionRelative(actionsBg, this.navigationContainer.width - 32, 4); + const iconAction = globalScene.add + .sprite(0, 0, "keyboard") + .setOrigin(0, -0.1) + .setPositionRelative(actionsBg, navWidth - 32, 4); this.navigationIcons["BUTTON_ACTION"] = iconAction; - const actionText = addTextObject(0, 0, i18next.t("settings:action"), TextStyle.SETTINGS_LABEL); - actionText.setOrigin(0, 0.15); + const actionText = addTextObject(0, 0, i18next.t("settings:action"), TextStyle.SETTINGS_LABEL).setOrigin(0, 0.15); actionText.setPositionRelative(iconAction, -actionText.width / 6 - 2, 0); - const iconCancel = globalScene.add.sprite(0, 0, "keyboard"); - iconCancel.setOrigin(0, -0.1); - iconCancel.setPositionRelative(actionsBg, actionText.x - 28, 4); + const iconCancel = globalScene.add + .sprite(0, 0, "keyboard") + .setOrigin(0, -0.1) + .setPositionRelative(actionsBg, actionText.x - 28, 4); this.navigationIcons["BUTTON_CANCEL"] = iconCancel; - const cancelText = addTextObject(0, 0, i18next.t("settings:back"), TextStyle.SETTINGS_LABEL); - cancelText.setOrigin(0, 0.15); + const cancelText = addTextObject(0, 0, i18next.t("settings:back"), TextStyle.SETTINGS_LABEL) // formatting + .setOrigin(0, 0.15); cancelText.setPositionRelative(iconCancel, -cancelText.width / 6 - 2, 0); - this.optionsContainer = globalScene.add.container(0, 0); + this.optionsContainer = globalScene.add.container(); this.settingLabels = []; this.optionValueLabels = []; @@ -113,8 +107,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { anyReloadRequired = true; } - this.settingLabels[s] = addTextObject(8, 28 + s * 16, settingName, TextStyle.SETTINGS_LABEL); - this.settingLabels[s].setOrigin(0, 0); + this.settingLabels[s] = addTextObject(8, 28 + s * 16, settingName, TextStyle.SETTINGS_LABEL).setOrigin(0); this.optionsContainer.add(this.settingLabels[s]); this.optionValueLabels.push( @@ -125,7 +118,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { option.label, setting.default === o ? TextStyle.SETTINGS_SELECTED : TextStyle.SETTINGS_VALUE, ); - valueLabel.setOrigin(0, 0); + valueLabel.setOrigin(0); this.optionsContainer.add(valueLabel); @@ -160,32 +153,33 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { this.scrollBar.setTotalRows(this.settings.length); // Two-lines message box - this.messageBoxContainer = globalScene.add.container(0, globalScene.scaledCanvas.height); - this.messageBoxContainer.setName("settings-message-box"); - this.messageBoxContainer.setVisible(false); + this.messageBoxContainer = globalScene.add + .container(0, globalScene.scaledCanvas.height) + .setName("settings-message-box") + .setVisible(false); const settingsMessageBox = addWindow(0, -1, globalScene.scaledCanvas.width - 2, 48); settingsMessageBox.setOrigin(0, 1); this.messageBoxContainer.add(settingsMessageBox); - const messageText = addTextObject(8, -40, "", TextStyle.WINDOW, { - maxLines: 2, - }); - messageText.setWordWrapWidth(globalScene.game.canvas.width - 60); - messageText.setName("settings-message"); - messageText.setOrigin(0, 0); + const messageText = addTextObject(8, -40, "", TextStyle.WINDOW, { maxLines: 2 }) + .setWordWrapWidth(globalScene.game.canvas.width - 60) + .setName("settings-message") + .setOrigin(0); this.messageBoxContainer.add(messageText); this.message = messageText; - this.settingsContainer.add(this.optionsBg); - this.settingsContainer.add(this.scrollBar); - this.settingsContainer.add(this.navigationContainer); - this.settingsContainer.add(actionsBg); - this.settingsContainer.add(this.optionsContainer); - this.settingsContainer.add(iconAction); - this.settingsContainer.add(iconCancel); - this.settingsContainer.add(actionText); + this.settingsContainer.add([ + this.optionsBg, + this.scrollBar, + this.navigationContainer, + actionsBg, + this.optionsContainer, + iconAction, + iconCancel, + actionText, + ]); // Only add the ReloadRequired text on pages that have settings that require a reload. if (anyReloadRequired) { const reloadRequired = addTextObject(0, 0, `*${i18next.t("settings:requireReload")}`, TextStyle.SETTINGS_LABEL) @@ -194,8 +188,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { .setY(actionText.y); this.settingsContainer.add(reloadRequired); } - this.settingsContainer.add(cancelText); - this.settingsContainer.add(this.messageBoxContainer); + this.settingsContainer.add([cancelText, this.messageBoxContainer]); ui.add(this.settingsContainer); @@ -210,17 +203,13 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { updateBindings(): void { for (const settingName of Object.keys(this.navigationIcons)) { if (settingName === "BUTTON_HOME") { - this.navigationIcons[settingName].setTexture("keyboard"); - this.navigationIcons[settingName].setFrame("HOME.png"); - this.navigationIcons[settingName].alpha = 1; + this.navigationIcons[settingName].setTexture("keyboard").setFrame("HOME.png").alpha = 1; continue; } const icon = globalScene.inputController?.getIconForLatestInputRecorded(settingName); if (icon) { const type = globalScene.inputController?.getLastSourceType(); - this.navigationIcons[settingName].setTexture(type); - this.navigationIcons[settingName].setFrame(icon); - this.navigationIcons[settingName].alpha = 1; + this.navigationIcons[settingName].setTexture(type).setFrame(icon).alpha = 1; } else { this.navigationIcons[settingName].alpha = 0; } @@ -242,21 +231,43 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { ? JSON.parse(localStorage.getItem(this.localStorageKey)!) : {}; // TODO: is this bang correct? - this.settings.forEach((setting, s) => - this.setOptionCursor(s, settings.hasOwnProperty(setting.key) ? settings[setting.key] : this.settings[s].default), - ); + this.settings.forEach((setting, s) => { + this.setOptionCursor(s, settings.hasOwnProperty(setting.key) ? settings[setting.key] : this.settings[s].default); + }); this.settingsContainer.setVisible(true); this.setCursor(0); this.setScrollCursor(0); - this.getUi().moveTo(this.settingsContainer, this.getUi().length - 1); + const ui = this.getUi(); - this.getUi().hideTooltip(); + ui.moveTo(this.settingsContainer, ui.length - 1); + + ui.hideTooltip(); return true; } + /** + * Submethod of {@linkcode processInput} to handle left/right input for changing option values + * + * @remarks + * If the cursor is positioned on a boundary option, will apply clamping / wrapping as appropriate + * @param cursor - Current cursor position in the settings menu + * @param dir - Direction to pan when scrolling, -1 for left, 1 for right + * @returns `true` if the action associated with the button was successfully processed, `false` otherwise. + */ + private processLeftRightInput(cursor: number, dir: -1 | 1): boolean { + let boundaryAction = Phaser.Math.Wrap; + let upperBound = this.optionValueLabels[cursor].length; + if (this.settings[cursor]?.clamp) { + boundaryAction = Phaser.Math.Clamp; + // clamping is right inclusive; wrapping isn't + upperBound -= 1; + } + return this.setOptionCursor(cursor, boundaryAction(this.optionCursors[cursor] + dir, 0, upperBound), true); + } + /** * Processes input from a specified button. * This method handles navigation through a UI menu, including movement through menu items @@ -314,20 +325,10 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { } break; case Button.LEFT: - // Cycle to the rightmost position when at the leftmost, otherwise move left - success = this.setOptionCursor( - cursor, - Phaser.Math.Wrap(this.optionCursors[cursor] - 1, 0, this.optionValueLabels[cursor].length), - true, - ); + success = this.processLeftRightInput(cursor, -1); break; case Button.RIGHT: - // Cycle to the leftmost position when at the rightmost, otherwise move right - success = this.setOptionCursor( - cursor, - Phaser.Math.Wrap(this.optionCursors[cursor] + 1, 0, this.optionValueLabels[cursor].length), - true, - ); + success = this.processLeftRightInput(cursor, 1); break; case Button.CYCLE_FORM: case Button.CYCLE_SHINY: @@ -376,8 +377,9 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { if (!this.cursorObj) { const cursorWidth = globalScene.scaledCanvas.width - (this.scrollBar.visible ? 16 : 10); - this.cursorObj = globalScene.add.nineslice(0, 0, "summary_moves_cursor", undefined, cursorWidth, 16, 1, 1, 1, 1); - this.cursorObj.setOrigin(0, 0); + this.cursorObj = globalScene.add + .nineslice(0, 0, "summary_moves_cursor", undefined, cursorWidth, 16, 1, 1, 1, 1) + .setOrigin(0); this.optionsContainer.add(this.cursorObj); } @@ -399,18 +401,21 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { settingIndex = this.cursor + this.scrollCursor; } const setting = this.settings[settingIndex]; - const lastCursor = this.optionCursors[settingIndex]; + // do nothing if the option isn't changing + if (cursor === lastCursor) { + return false; + } - const lastValueLabel = this.optionValueLabels[settingIndex][lastCursor]; - lastValueLabel.setColor(getTextColor(TextStyle.SETTINGS_VALUE)); - lastValueLabel.setShadowColor(getTextColor(TextStyle.SETTINGS_VALUE, true)); + this.optionValueLabels[settingIndex][lastCursor] + .setColor(getTextColor(TextStyle.SETTINGS_VALUE)) + .setShadowColor(getTextColor(TextStyle.SETTINGS_VALUE, true)); this.optionCursors[settingIndex] = cursor; - const newValueLabel = this.optionValueLabels[settingIndex][cursor]; - newValueLabel.setColor(getTextColor(TextStyle.SETTINGS_SELECTED)); - newValueLabel.setShadowColor(getTextColor(TextStyle.SETTINGS_SELECTED, true)); + this.optionValueLabels[settingIndex][cursor] + .setColor(getTextColor(TextStyle.SETTINGS_SELECTED)) + .setShadowColor(getTextColor(TextStyle.SETTINGS_SELECTED, true)); if (save) { const saveSetting = () => { @@ -511,7 +516,7 @@ export class AbstractSettingsUiHandler extends MessageUiHandler { override showText( text: string, delay?: number, - callback?: Function, + callback?: AnyFn, callbackDelay?: number, prompt?: boolean, promptDelay?: number, diff --git a/src/ui/settings/gamepad-binding-ui-handler.ts b/src/ui/settings/gamepad-binding-ui-handler.ts index 4fdc4abdbfe..93923aeb57d 100644 --- a/src/ui/settings/gamepad-binding-ui-handler.ts +++ b/src/ui/settings/gamepad-binding-ui-handler.ts @@ -3,7 +3,7 @@ import { Device } from "#enums/devices"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; import { getIconWithSettingName, getKeyWithKeycode } from "#inputs/config-handler"; -import { AbstractBindingUiHandler } from "#ui/handlers/abstract-binding-ui-handler"; +import { AbstractBindingUiHandler } from "#ui/abstract-binding-ui-handler"; import { addTextObject } from "#ui/text"; import i18next from "i18next"; diff --git a/src/ui/settings/keyboard-binding-ui-handler.ts b/src/ui/settings/keyboard-binding-ui-handler.ts index b1fd153461f..b339ac16188 100644 --- a/src/ui/settings/keyboard-binding-ui-handler.ts +++ b/src/ui/settings/keyboard-binding-ui-handler.ts @@ -3,7 +3,7 @@ import { Device } from "#enums/devices"; import { TextStyle } from "#enums/text-style"; import type { UiMode } from "#enums/ui-mode"; import { getKeyWithKeycode } from "#inputs/config-handler"; -import { AbstractBindingUiHandler } from "#ui/handlers/abstract-binding-ui-handler"; +import { AbstractBindingUiHandler } from "#ui/abstract-binding-ui-handler"; import { addTextObject } from "#ui/text"; import i18next from "i18next"; diff --git a/src/ui/settings/move-touch-controls-handler.ts b/src/ui/settings/move-touch-controls-handler.ts index 248ee76a850..dd7bceec55e 100644 --- a/src/ui/settings/move-touch-controls-handler.ts +++ b/src/ui/settings/move-touch-controls-handler.ts @@ -197,7 +197,7 @@ export class MoveTouchControlsHandler { /** * Returns the current positions of all touch controls that have moved from their default positions of this orientation. - * @returns {ControlPosition[]} The current positions of all touch controls that have moved from their default positions of this orientation + * @returns The current positions of all touch controls that have moved from their default positions of this orientation */ private getModifiedCurrentPositions(): ControlPosition[] { return this.getControlGroupElements() diff --git a/src/ui/settings/option-select-ui-handler.ts b/src/ui/settings/option-select-ui-handler.ts index 235f16e7f09..c989c768244 100644 --- a/src/ui/settings/option-select-ui-handler.ts +++ b/src/ui/settings/option-select-ui-handler.ts @@ -1,5 +1,5 @@ import { UiMode } from "#enums/ui-mode"; -import { AbstractOptionSelectUiHandler } from "#ui/handlers/abstract-option-select-ui-handler"; +import { AbstractOptionSelectUiHandler } from "#ui/abstract-option-select-ui-handler"; export class OptionSelectUiHandler extends AbstractOptionSelectUiHandler { constructor(mode: UiMode = UiMode.OPTION_SELECT) { diff --git a/src/ui/settings/settings-gamepad-ui-handler.ts b/src/ui/settings/settings-gamepad-ui-handler.ts index 57a70411f4c..5c8f187f4f8 100644 --- a/src/ui/settings/settings-gamepad-ui-handler.ts +++ b/src/ui/settings/settings-gamepad-ui-handler.ts @@ -18,11 +18,7 @@ import { addTextObject } from "#ui/text"; import { truncateString } from "#utils/common"; import i18next from "i18next"; -/** - * Class representing the settings UI handler for gamepads. - * - * @extends AbstractControlSettingsUiHandler - */ +/** Class representing the settings UI handler for gamepads */ export class SettingsGamepadUiHandler extends AbstractControlSettingsUiHandler { /** diff --git a/src/ui/settings/settings-keyboard-ui-handler.ts b/src/ui/settings/settings-keyboard-ui-handler.ts index 295a71abe36..f802a4fa9cc 100644 --- a/src/ui/settings/settings-keyboard-ui-handler.ts +++ b/src/ui/settings/settings-keyboard-ui-handler.ts @@ -19,11 +19,7 @@ import { truncateString } from "#utils/common"; import { toPascalSnakeCase } from "#utils/strings"; import i18next from "i18next"; -/** - * Class representing the settings UI handler for keyboards. - * - * @extends AbstractControlSettingsUiHandler - */ +/** Class representing the settings UI handler for keyboards */ export class SettingsKeyboardUiHandler extends AbstractControlSettingsUiHandler { /** * Creates an instance of SettingsKeyboardUiHandler. diff --git a/src/ui/ui.ts b/src/ui/ui.ts index a8e4dbe7318..76b07d7bfa5 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -4,59 +4,59 @@ import { Device } from "#enums/devices"; import { PlayerGender } from "#enums/player-gender"; import { TextStyle } from "#enums/text-style"; import { UiMode } from "#enums/ui-mode"; -import { AchvBar } from "#ui/containers/achv-bar"; -import type { BgmBar } from "#ui/containers/bgm-bar"; -import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler"; -import { SavingIconHandler } from "#ui/containers/saving-icon-handler"; +import { AchvBar } from "#ui/achv-bar"; +import { AchvsUiHandler } from "#ui/achvs-ui-handler"; +import { AutoCompleteUiHandler } from "#ui/autocomplete-ui-handler"; +import { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; +import { BallUiHandler } from "#ui/ball-ui-handler"; +import { BattleMessageUiHandler } from "#ui/battle-message-ui-handler"; +import type { BgmBar } from "#ui/bgm-bar"; +import { GameChallengesUiHandler } from "#ui/challenges-select-ui-handler"; +import { ChangePasswordFormUiHandler } from "#ui/change-password-form-ui-handler"; +import { CommandUiHandler } from "#ui/command-ui-handler"; +import { ConfirmUiHandler } from "#ui/confirm-ui-handler"; +import { EggGachaUiHandler } from "#ui/egg-gacha-ui-handler"; +import { EggHatchSceneUiHandler } from "#ui/egg-hatch-scene-ui-handler"; +import { EggListUiHandler } from "#ui/egg-list-ui-handler"; +import { EggSummaryUiHandler } from "#ui/egg-summary-ui-handler"; +import { EvolutionSceneUiHandler } from "#ui/evolution-scene-ui-handler"; +import { FightUiHandler } from "#ui/fight-ui-handler"; +import { GameStatsUiHandler } from "#ui/game-stats-ui-handler"; import { GamepadBindingUiHandler } from "#ui/gamepad-binding-ui-handler"; -import { AchvsUiHandler } from "#ui/handlers/achvs-ui-handler"; -import { AutoCompleteUiHandler } from "#ui/handlers/autocomplete-ui-handler"; -import { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; -import { BallUiHandler } from "#ui/handlers/ball-ui-handler"; -import { BattleMessageUiHandler } from "#ui/handlers/battle-message-ui-handler"; -import { GameChallengesUiHandler } from "#ui/handlers/challenges-select-ui-handler"; -import { ChangePasswordFormUiHandler } from "#ui/handlers/change-password-form-ui-handler"; -import { CommandUiHandler } from "#ui/handlers/command-ui-handler"; -import { ConfirmUiHandler } from "#ui/handlers/confirm-ui-handler"; -import { EggGachaUiHandler } from "#ui/handlers/egg-gacha-ui-handler"; -import { EggHatchSceneHandler } from "#ui/handlers/egg-hatch-scene-handler"; -import { EggListUiHandler } from "#ui/handlers/egg-list-ui-handler"; -import { EggSummaryUiHandler } from "#ui/handlers/egg-summary-ui-handler"; -import { EvolutionSceneHandler } from "#ui/handlers/evolution-scene-handler"; -import { FightUiHandler } from "#ui/handlers/fight-ui-handler"; -import { GameStatsUiHandler } from "#ui/handlers/game-stats-ui-handler"; -import { LoadingModalUiHandler } from "#ui/handlers/loading-modal-ui-handler"; -import { LoginFormUiHandler } from "#ui/handlers/login-form-ui-handler"; -import { MenuUiHandler } from "#ui/handlers/menu-ui-handler"; -import { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; -import { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler"; -import { PartyUiHandler } from "#ui/handlers/party-ui-handler"; -import { PokedexScanUiHandler } from "#ui/handlers/pokedex-scan-ui-handler"; -import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler"; -import { RegistrationFormUiHandler } from "#ui/handlers/registration-form-ui-handler"; -import { RenameFormUiHandler } from "#ui/handlers/rename-form-ui-handler"; -import { RunHistoryUiHandler } from "#ui/handlers/run-history-ui-handler"; -import { RunInfoUiHandler } from "#ui/handlers/run-info-ui-handler"; -import { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler"; -import { SessionReloadModalUiHandler } from "#ui/handlers/session-reload-modal-ui-handler"; -import { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler"; -import { SummaryUiHandler } from "#ui/handlers/summary-ui-handler"; -import { TargetSelectUiHandler } from "#ui/handlers/target-select-ui-handler"; -import { TestDialogueUiHandler } from "#ui/handlers/test-dialogue-ui-handler"; -import { TitleUiHandler } from "#ui/handlers/title-ui-handler"; -import type { UiHandler } from "#ui/handlers/ui-handler"; -import { UnavailableModalUiHandler } from "#ui/handlers/unavailable-modal-ui-handler"; import { KeyboardBindingUiHandler } from "#ui/keyboard-binding-ui-handler"; +import { LoadingModalUiHandler } from "#ui/loading-modal-ui-handler"; +import { LoginFormUiHandler } from "#ui/login-form-ui-handler"; +import { MenuUiHandler } from "#ui/menu-ui-handler"; +import { MessageUiHandler } from "#ui/message-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler"; import { NavigationManager } from "#ui/navigation-menu"; import { OptionSelectUiHandler } from "#ui/option-select-ui-handler"; +import { PartyUiHandler } from "#ui/party-ui-handler"; +import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler"; +import { PokedexScanUiHandler } from "#ui/pokedex-scan-ui-handler"; +import { PokedexUiHandler } from "#ui/pokedex-ui-handler"; +import { RegistrationFormUiHandler } from "#ui/registration-form-ui-handler"; +import { RenameFormUiHandler } from "#ui/rename-form-ui-handler"; +import { RunHistoryUiHandler } from "#ui/run-history-ui-handler"; +import { RunInfoUiHandler } from "#ui/run-info-ui-handler"; +import { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler"; +import { SavingIconContainer } from "#ui/saving-icon-handler"; +import { SessionReloadModalUiHandler } from "#ui/session-reload-modal-ui-handler"; import { SettingsAudioUiHandler } from "#ui/settings-audio-ui-handler"; import { SettingsDisplayUiHandler } from "#ui/settings-display-ui-handler"; import { SettingsGamepadUiHandler } from "#ui/settings-gamepad-ui-handler"; import { SettingsKeyboardUiHandler } from "#ui/settings-keyboard-ui-handler"; import { SettingsUiHandler } from "#ui/settings-ui-handler"; +import { StarterSelectUiHandler } from "#ui/starter-select-ui-handler"; +import { SummaryUiHandler } from "#ui/summary-ui-handler"; +import { TargetSelectUiHandler } from "#ui/target-select-ui-handler"; +import { TestDialogueUiHandler } from "#ui/test-dialogue-ui-handler"; import { addTextObject } from "#ui/text"; +import { TitleUiHandler } from "#ui/title-ui-handler"; +import type { UiHandler } from "#ui/ui-handler"; import { addWindow } from "#ui/ui-theme"; +import { UnavailableModalUiHandler } from "#ui/unavailable-modal-ui-handler"; import { executeIf } from "#utils/common"; import i18next from "i18next"; import { AdminUiHandler } from "./handlers/admin-ui-handler"; @@ -115,7 +115,7 @@ export class UI extends Phaser.GameObjects.Container { private overlay: Phaser.GameObjects.Rectangle; public achvBar: AchvBar; public bgmBar: BgmBar; - public savingIcon: SavingIconHandler; + public savingIcon: SavingIconContainer; private tooltipContainer: Phaser.GameObjects.Container; private tooltipBg: Phaser.GameObjects.NineSlice; @@ -141,8 +141,8 @@ export class UI extends Phaser.GameObjects.Container { new PartyUiHandler(), new SummaryUiHandler(), new StarterSelectUiHandler(), - new EvolutionSceneHandler(), - new EggHatchSceneHandler(), + new EvolutionSceneUiHandler(), + new EggHatchSceneUiHandler(), new EggSummaryUiHandler(), new ConfirmUiHandler(), new OptionSelectUiHandler(), @@ -198,7 +198,7 @@ export class UI extends Phaser.GameObjects.Container { globalScene.uiContainer.add(this.achvBar); - this.savingIcon = new SavingIconHandler(); + this.savingIcon = new SavingIconContainer(); this.savingIcon.setup(); globalScene.uiContainer.add(this.savingIcon); diff --git a/src/ui/handlers/pokemon-icon-anim-handler.ts b/src/ui/utils/pokemon-icon-anim-helper.ts similarity index 98% rename from src/ui/handlers/pokemon-icon-anim-handler.ts rename to src/ui/utils/pokemon-icon-anim-helper.ts index 408e0ebc9d3..0d8de7ce1ca 100644 --- a/src/ui/handlers/pokemon-icon-anim-handler.ts +++ b/src/ui/utils/pokemon-icon-anim-helper.ts @@ -9,7 +9,7 @@ export enum PokemonIconAnimMode { type PokemonIcon = Phaser.GameObjects.Container | Phaser.GameObjects.Sprite; -export class PokemonIconAnimHandler { +export class PokemonIconAnimHelper { private icons: Map; private toggled: boolean; diff --git a/src/ui/handlers/scrollable-grid-handler.ts b/src/ui/utils/scrollable-grid-helper.ts similarity index 96% rename from src/ui/handlers/scrollable-grid-handler.ts rename to src/ui/utils/scrollable-grid-helper.ts index 12bbaa32e98..74ddfdfa412 100644 --- a/src/ui/handlers/scrollable-grid-handler.ts +++ b/src/ui/utils/scrollable-grid-helper.ts @@ -1,6 +1,6 @@ import { Button } from "#enums/buttons"; -import type { ScrollBar } from "#ui/containers/scroll-bar"; -import type { UiHandler } from "#ui/handlers/ui-handler"; +import type { ScrollBar } from "#ui/scroll-bar"; +import type { UiHandler } from "#ui/ui-handler"; type UpdateGridCallbackFunction = () => void; type UpdateDetailsCallbackFunction = (index: number) => void; @@ -16,7 +16,7 @@ type UpdateDetailsCallbackFunction = (index: number) => void; * - in `UiHandler.processInput`: call `processNavigationInput` to have it handle the cursor updates while calling the defined callbacks * - in `UiHandler.clear`: call `reset` */ -export class ScrollableGridUiHandler { +export class ScrollableGridHelper { private readonly ROWS: number; private readonly COLUMNS: number; private handler: UiHandler; @@ -47,7 +47,7 @@ export class ScrollableGridUiHandler { * @param scrollBar {@linkcode ScrollBar} * @returns this */ - withScrollBar(scrollBar: ScrollBar): ScrollableGridUiHandler { + withScrollBar(scrollBar: ScrollBar): ScrollableGridHelper { this.scrollBar = scrollBar; this.scrollBar.setTotalRows(Math.ceil(this.totalElements / this.COLUMNS)); return this; @@ -58,7 +58,7 @@ export class ScrollableGridUiHandler { * @param callback {@linkcode UpdateGridCallbackFunction} * @returns this */ - withUpdateGridCallBack(callback: UpdateGridCallbackFunction): ScrollableGridUiHandler { + withUpdateGridCallBack(callback: UpdateGridCallbackFunction): ScrollableGridHelper { this.updateGridCallback = callback; return this; } @@ -68,7 +68,7 @@ export class ScrollableGridUiHandler { * @param callback {@linkcode UpdateDetailsCallbackFunction} * @returns this */ - withUpdateSingleElementCallback(callback: UpdateDetailsCallbackFunction): ScrollableGridUiHandler { + withUpdateSingleElementCallback(callback: UpdateDetailsCallbackFunction): ScrollableGridHelper { this.updateDetailsCallback = callback; return this; } diff --git a/src/utils/challenge-utils.ts b/src/utils/challenge-utils.ts index 10f834e24b4..f79f48f30d2 100644 --- a/src/utils/challenge-utils.ts +++ b/src/utils/challenge-utils.ts @@ -12,8 +12,8 @@ import type { MoveSourceType } from "#enums/move-source-type"; import type { SpeciesId } from "#enums/species-id"; import type { EnemyPokemon, PlayerPokemon, Pokemon } from "#field/pokemon"; import type { ModifierTypeOption } from "#modifiers/modifier-type"; -import type { DexAttrProps, StarterDataEntry } from "#system/game-data"; import type { DexEntry } from "#types/dex-data"; +import type { DexAttrProps, StarterDataEntry } from "#types/save-data"; import { BooleanHolder, type NumberHolder } from "./common"; import { getPokemonSpecies } from "./pokemon-utils"; @@ -204,7 +204,7 @@ export function applyChallenges(challengeType: ChallengeType.SHOP, status: Boole * @param challengeType - {@linkcode ChallengeType.POKEMON_ADD_TO_PARTY} * @param pokemon - The pokemon being caught * @param status - Whether the pokemon can be added to the party or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges( challengeType: ChallengeType.POKEMON_ADD_TO_PARTY, @@ -217,7 +217,7 @@ export function applyChallenges( * @param challengeType - {@linkcode ChallengeType.POKEMON_FUSION} * @param pokemon - The pokemon being checked * @param status - Whether the selected pokemon is allowed to fuse or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges( challengeType: ChallengeType.POKEMON_FUSION, @@ -230,7 +230,7 @@ export function applyChallenges( * @param challengeType - {@linkcode ChallengeType.POKEMON_MOVE} * @param moveId - The move being checked * @param status - Whether the move can be used or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges( challengeType: ChallengeType.POKEMON_MOVE, @@ -243,7 +243,7 @@ export function applyChallenges( * @param challengeType - {@linkcode ChallengeType.SHOP_ITEM} * @param shopItem - The item being checked * @param status - Whether the item should be added to the shop or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges( challengeType: ChallengeType.SHOP_ITEM, @@ -256,7 +256,7 @@ export function applyChallenges( * @param challengeType - {@linkcode ChallengeType.WAVE_REWARD} * @param reward - The reward being checked * @param status - Whether the reward should be added to the reward options or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges( challengeType: ChallengeType.WAVE_REWARD, @@ -268,7 +268,7 @@ export function applyChallenges( * Apply all challenges that prevent recovery from fainting * @param challengeType - {@linkcode ChallengeType.PREVENT_REVIVE} * @param status - Whether fainting is a permanent status or not - * @return `true` if any challenge was sucessfully applied, `false` otherwise + * @returns `true` if any challenge was sucessfully applied, `false` otherwise */ export function applyChallenges(challengeType: ChallengeType.PREVENT_REVIVE, status: BooleanHolder): boolean; diff --git a/src/utils/common.ts b/src/utils/common.ts index 97e61b902d8..2734b075a53 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -135,8 +135,8 @@ export function randSeedItem(items: T[]): T { /** * Shuffle a list using the seeded rng. Utilises the Fisher-Yates algorithm. - * @param {Array} items An array of items. - * @returns {Array} A new shuffled array of items. + * @param items An array of items. + * @returns A new shuffled array of items. */ export function randSeedShuffle(items: T[]): T[] { if (items.length <= 1) { @@ -340,8 +340,8 @@ export function rgbToHsv(r: number, g: number, b: number) { /** * Compare color difference in RGB - * @param {Array} rgb1 First RGB color in array - * @param {Array} rgb2 Second RGB color in array + * @param rgb1 First RGB color in array + * @param rgb2 Second RGB color in array */ export function deltaRgb(rgb1: number[], rgb2: number[]): number { const [r1, g1, b1] = rgb1; diff --git a/src/utils/data.ts b/src/utils/data.ts index 8ff308cde8f..1383d8e6ff2 100644 --- a/src/utils/data.ts +++ b/src/utils/data.ts @@ -1,6 +1,6 @@ import { loggedInUser } from "#app/account"; import { saveKey } from "#app/constants"; -import type { StarterAttributes } from "#system/game-data"; +import type { StarterAttributes } from "#types/save-data"; import { AES, enc } from "crypto-js"; /** diff --git a/src/utils/strings.ts b/src/utils/strings.ts index bf5e5c6473f..b4b2498fe9d 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -62,7 +62,7 @@ function trimFromStartAndEnd(str: string, charToTrim: string): string { /** * Capitalize the first letter of a string. * @param str - The string whose first letter is to be capitalized - * @return The original string with its first letter capitalized. + * @returns The original string with its first letter capitalized. * @example * ```ts * console.log(capitalizeFirstLetter("consectetur adipiscing elit")); // returns "Consectetur adipiscing elit" diff --git a/test/@types/vitest.d.ts b/test/@types/vitest.d.ts index b13d9e53101..9a6f07b4afb 100644 --- a/test/@types/vitest.d.ts +++ b/test/@types/vitest.d.ts @@ -27,6 +27,8 @@ import type { toHaveBattlerTagOptions } from "#test/test-utils/matchers/to-have- declare module "vitest" { interface Assertion { + // #region Generic Matchers + /** * Check whether an array contains EXACTLY the given items (in any order). * @@ -38,11 +40,20 @@ declare module "vitest" { */ toEqualArrayUnsorted(expected: T[]): void; + // #endregion Generic Matchers + + // #region GameManager Matchers + + /** + * Check if the {@linkcode GameManager} has shown the given message at least once in the current battle. + * @param expectedMessage - The expected message + */ + toHaveShownMessage(expectedMessage: string): void; /** - * Check if the currently-running {@linkcode Phase} is of the given type. * @param expectedPhase - The expected {@linkcode PhaseString} */ toBeAtPhase(expectedPhase: PhaseString): void; + // #endregion GameManager Matchers // #region Arena Matchers diff --git a/test/abilities/arena-trap.test.ts b/test/abilities/arena-trap.test.ts index d43148dce7b..8f5d820a145 100644 --- a/test/abilities/arena-trap.test.ts +++ b/test/abilities/arena-trap.test.ts @@ -6,7 +6,7 @@ import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { GameManager } from "#test/test-utils/game-manager"; -import type { PartyUiHandler } from "#ui/handlers/party-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -57,7 +57,7 @@ describe("Abilities - Arena Trap", () => { await game.phaseInterceptor.to("CommandPhase"); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("abilityTriggers:arenaTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(enemy), abilityName: allAbilities[AbilityId.ARENA_TRAP].name, diff --git a/test/abilities/cud-chew.test.ts b/test/abilities/cud-chew.test.ts index ae3b4ad8765..8d80ba119ca 100644 --- a/test/abilities/cud-chew.test.ts +++ b/test/abilities/cud-chew.test.ts @@ -99,7 +99,7 @@ describe("Abilities - Cud Chew", () => { expect(abDisplaySpy.mock.calls[1][2]).toBe(false); // should display messgae - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("battle:hpIsFull", { pokemonName: getPokemonNameWithAffix(farigiraf), }), diff --git a/test/abilities/flower-gift.test.ts b/test/abilities/flower-gift.test.ts index 01459cd4e1e..6d8641917aa 100644 --- a/test/abilities/flower-gift.test.ts +++ b/test/abilities/flower-gift.test.ts @@ -18,8 +18,8 @@ describe("Abilities - Flower Gift", () => { /** * Tests reverting to normal form when Cloud Nine/Air Lock is active on the field - * @param {GameManager} game The game manager instance - * @param {AbilityId} ability The ability that is active on the field + * @param game The game manager instance + * @param ability The ability that is active on the field */ const testRevertFormAgainstAbility = async (game: GameManager, ability: AbilityId) => { game.override.starterForms({ [SpeciesId.CASTFORM]: SUNSHINE_FORM }).enemyAbility(ability); diff --git a/test/abilities/gulp-missile.test.ts b/test/abilities/gulp-missile.test.ts index 865a319251f..82f446623f8 100644 --- a/test/abilities/gulp-missile.test.ts +++ b/test/abilities/gulp-missile.test.ts @@ -21,7 +21,7 @@ describe("Abilities - Gulp Missile", () => { /** * Gets the effect damage of Gulp Missile * See Gulp Missile {@link https://bulbapedia.bulbagarden.net/wiki/Gulp_Missile_(Ability)} - * @param {Pokemon} pokemon The pokemon taking the effect damage. + * @param pokemon The pokemon taking the effect damage. * @returns The effect damage of Gulp Missile */ const getEffectDamage = (pokemon: Pokemon): number => { diff --git a/test/abilities/truant.test.ts b/test/abilities/truant.test.ts index 0d71cd393b0..31098fa1a85 100644 --- a/test/abilities/truant.test.ts +++ b/test/abilities/truant.test.ts @@ -54,7 +54,7 @@ describe("Ability - Truant", () => { expect(player.getLastXMoves(1)[0]).toEqual(expect.objectContaining({ move: MoveId.NONE, result: MoveResult.FAIL })); expect(enemy.hp).toBe(enemy.getMaxHp()); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("battlerTags:truantLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(player), }), diff --git a/test/challenges/hardcore.test.ts b/test/challenges/hardcore.test.ts index a52d7102868..0f4ab1b9f02 100644 --- a/test/challenges/hardcore.test.ts +++ b/test/challenges/hardcore.test.ts @@ -8,7 +8,7 @@ import { SpeciesId } from "#enums/species-id"; import { StatusEffect } from "#enums/status-effect"; import { UiMode } from "#enums/ui-mode"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/challenges/limited-support.test.ts b/test/challenges/limited-support.test.ts index ba8930943dd..35413220550 100644 --- a/test/challenges/limited-support.test.ts +++ b/test/challenges/limited-support.test.ts @@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { ExpBoosterModifier } from "#modifiers/modifier"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/daily-mode.test.ts b/test/daily-mode.test.ts index fae12a0b5d7..34a8da80478 100644 --- a/test/daily-mode.test.ts +++ b/test/daily-mode.test.ts @@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { MapModifier } from "#modifiers/modifier"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Daily Mode", () => { diff --git a/test/imports.test.ts b/test/imports.test.ts deleted file mode 100644 index aeaa763c05e..00000000000 --- a/test/imports.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { initStatsKeys } from "#ui/handlers/game-stats-ui-handler"; -import { describe, expect, it } from "vitest"; - -async function importModule() { - try { - initStatsKeys(); - const { PokemonMove } = await import("#app/data/moves/pokemon-move"); - const { SpeciesId: Species } = await import("#enums/species-id"); - return { - PokemonMove, - Species, - }; - // Dynamically import the module - } catch (error) { - // Log the error stack trace - console.error("Error during import:", error.stack); - // Rethrow the error to ensure the test fails - throw error; - } -} - -describe("tests to debug the import, with trace", () => { - it("import PokemonMove module", async () => { - const module = await importModule(); - // Example assertion - expect(module.PokemonMove).toBeDefined(); - }); - - it("import Species module", async () => { - const module = await importModule(); - // Example assertion - expect(module.Species).toBeDefined(); - }); -}); diff --git a/test/items/dire-hit.test.ts b/test/items/dire-hit.test.ts index d704a94f3a8..6d4bc7524eb 100644 --- a/test/items/dire-hit.test.ts +++ b/test/items/dire-hit.test.ts @@ -10,7 +10,7 @@ import { NewBattlePhase } from "#phases/new-battle-phase"; import { TurnEndPhase } from "#phases/turn-end-phase"; import { TurnInitPhase } from "#phases/turn-init-phase"; import { GameManager } from "#test/test-utils/game-manager"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/items/double-battle-chance-booster.test.ts b/test/items/double-battle-chance-booster.test.ts index 9985d4b3a55..2c12b34eba3 100644 --- a/test/items/double-battle-chance-booster.test.ts +++ b/test/items/double-battle-chance-booster.test.ts @@ -5,7 +5,7 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { DoubleBattleChanceBoosterModifier } from "#modifiers/modifier"; import { GameManager } from "#test/test-utils/game-manager"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/items/temp-stat-stage-booster.test.ts b/test/items/temp-stat-stage-booster.test.ts index 499f1d630b0..05ea5a03eae 100644 --- a/test/items/temp-stat-stage-booster.test.ts +++ b/test/items/temp-stat-stage-booster.test.ts @@ -7,7 +7,7 @@ import { BATTLE_STATS, Stat } from "#enums/stat"; import { UiMode } from "#enums/ui-mode"; import { TempStatStageBoosterModifier } from "#modifiers/modifier"; import { GameManager } from "#test/test-utils/game-manager"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/moves/chilly-reception.test.ts b/test/moves/chilly-reception.test.ts index 096454132f3..f9caea3d560 100644 --- a/test/moves/chilly-reception.test.ts +++ b/test/moves/chilly-reception.test.ts @@ -47,7 +47,7 @@ describe("Moves - Chilly Reception", () => { expect(game.field.getPlayerPokemon()).toBe(meowth); expect(slowking.isOnField()).toBe(false); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:chillyReception", { pokemonName: getPokemonNameWithAffix(slowking) }), ); }); @@ -110,7 +110,7 @@ describe("Moves - Chilly Reception", () => { expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); expect(game.field.getPlayerPokemon()).toBe(slowking); expect(slowking.getLastXMoves()[0].result).toBe(MoveResult.FAIL); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:chillyReception", { pokemonName: getPokemonNameWithAffix(slowking) }), ); }); @@ -129,7 +129,7 @@ describe("Moves - Chilly Reception", () => { expect(game.field.getPlayerPokemon()).toBe(meowth); expect(slowking.isOnField()).toBe(false); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.textInterceptor.logs).not.toContain( + expect(game).not.toHaveShownMessage( i18next.t("moveTriggers:chillyReception", { pokemonName: getPokemonNameWithAffix(slowking) }), ); }); diff --git a/test/moves/delayed-attack.test.ts b/test/moves/delayed-attack.test.ts index f8973adc9c5..8e1708e44a2 100644 --- a/test/moves/delayed-attack.test.ts +++ b/test/moves/delayed-attack.test.ts @@ -99,7 +99,7 @@ describe("Moves - Delayed Attacks", () => { expectFutureSightActive(0); const enemy = game.field.getEnemyPokemon(); expect(enemy).not.toHaveFullHp(); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(enemy), moveName: allMoves[move].name, @@ -227,7 +227,7 @@ describe("Moves - Delayed Attacks", () => { expect(karp).toHaveFullHp(); expect(feebas).toHaveFullHp(); - expect(game.textInterceptor.logs).not.toContain( + expect(game).not.toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(karp), moveName: allMoves[MoveId.FUTURE_SIGHT].name, @@ -256,7 +256,7 @@ describe("Moves - Delayed Attacks", () => { await passTurns(2); expect(enemy1).not.toHaveFullHp(); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(enemy1), moveName: allMoves[MoveId.FUTURE_SIGHT].name, @@ -284,7 +284,7 @@ describe("Moves - Delayed Attacks", () => { expectFutureSightActive(0); expect(enemy1).toHaveFullHp(); - expect(game.textInterceptor.logs).not.toContain( + expect(game).not.toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(enemy1), moveName: allMoves[MoveId.FUTURE_SIGHT].name, @@ -321,7 +321,7 @@ describe("Moves - Delayed Attacks", () => { expect(enemy1).toHaveFullHp(); expect(enemy2).not.toHaveFullHp(); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(enemy2), moveName: allMoves[MoveId.FUTURE_SIGHT].name, @@ -354,7 +354,7 @@ describe("Moves - Delayed Attacks", () => { // Player Normalize was not applied due to being off field const enemy = game.field.getEnemyPokemon(); expect(enemy).not.toHaveFullHp(); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(enemy), moveName: allMoves[MoveId.DOOM_DESIRE].name, diff --git a/test/moves/flame-burst.test.ts b/test/moves/flame-burst.test.ts index ce82b46d0fc..e340936f94c 100644 --- a/test/moves/flame-burst.test.ts +++ b/test/moves/flame-burst.test.ts @@ -16,7 +16,7 @@ describe("Moves - Flame Burst", () => { * Calculates the effect damage of Flame Burst which is 1/16 of the target ally's max HP * See Flame Burst {@link https://bulbapedia.bulbagarden.net/wiki/Flame_Burst_(move)} * See Flame Burst's move attribute {@linkcode FlameBurstAttr} - * @param pokemon {@linkcode Pokemon} - The ally of the move's target + * @param pokemon - The ally of the move's target * @returns Effect damage of Flame Burst */ const getEffectDamage = (pokemon: Pokemon): number => { diff --git a/test/moves/laser-focus.test.ts b/test/moves/laser-focus.test.ts new file mode 100644 index 00000000000..7496e3ed87f --- /dev/null +++ b/test/moves/laser-focus.test.ts @@ -0,0 +1,104 @@ +import { getPokemonNameWithAffix } from "#app/messages"; +import { AbilityId } from "#enums/ability-id"; +import { BattlerIndex } from "#enums/battler-index"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { MoveId } from "#enums/move-id"; +import { SpeciesId } from "#enums/species-id"; +import { GameManager } from "#test/test-utils/game-manager"; +import i18next from "i18next"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Move - Laser Focus", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .ability(AbilityId.BALL_FETCH) + .battleStyle("single") + .criticalHits(false) + .enemySpecies(SpeciesId.MAGIKARP) + .enemyAbility(AbilityId.BALL_FETCH) + .enemyMoveset(MoveId.SPLASH) + .startingLevel(100) + .enemyLevel(100); + }); + + it("should make the user's next attack a guaranteed critical hit", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); + + game.move.use(MoveId.LASER_FOCUS); + await game.toNextTurn(); + + const feebas = game.field.getPlayerPokemon(); + expect(feebas).toHaveBattlerTag(BattlerTagType.ALWAYS_CRIT); + expect(game).toHaveShownMessage( + i18next.t("battlerTags:laserFocusOnAdd", { + pokemonNameWithAffix: getPokemonNameWithAffix(feebas), + }), + ); + + const enemy = game.field.getEnemyPokemon(); + const critSpy = vi.spyOn(enemy, "getCriticalHitResult"); + + game.move.use(MoveId.TACKLE); + await game.toEndOfTurn(); + + expect(critSpy).toHaveLastReturnedWith(true); + }); + + it("should disappear at the end of the next turn", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); + + const feebas = game.field.getPlayerPokemon(); + + game.move.use(MoveId.LASER_FOCUS); + await game.toNextTurn(); + + expect(feebas).toHaveBattlerTag(BattlerTagType.ALWAYS_CRIT); + + game.move.use(MoveId.SPLASH); + await game.toNextTurn(); + + expect(feebas).not.toHaveBattlerTag(BattlerTagType.ALWAYS_CRIT); + + const enemy = game.field.getEnemyPokemon(); + const critSpy = vi.spyOn(enemy, "getCriticalHitResult"); + + game.move.use(MoveId.TACKLE); + await game.toEndOfTurn(); + + expect(critSpy).toHaveLastReturnedWith(false); + }); + + it("should boost all attacks until the end of the next turn", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); + + game.move.use(MoveId.LASER_FOCUS); + await game.toNextTurn(); + + const enemy = game.field.getEnemyPokemon(); + const critSpy = vi.spyOn(enemy, "getCriticalHitResult"); + + game.move.use(MoveId.TACKLE); + await game.move.forceEnemyMove(MoveId.INSTRUCT); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.toEndOfTurn(); + + expect(critSpy).toHaveReturnedTimes(2); + expect(critSpy).toHaveNthReturnedWith(1, true); + expect(critSpy).toHaveNthReturnedWith(2, true); + }); +}); diff --git a/test/moves/splash-celebrate.test.ts b/test/moves/splash-celebrate.test.ts new file mode 100644 index 00000000000..346ffedd12c --- /dev/null +++ b/test/moves/splash-celebrate.test.ts @@ -0,0 +1,52 @@ +import { loggedInUser } from "#app/account"; +import { AbilityId } from "#enums/ability-id"; +import { MoveId } from "#enums/move-id"; +import { SpeciesId } from "#enums/species-id"; +import { GameManager } from "#test/test-utils/game-manager"; +import i18next from "i18next"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe.each<{ name: string; move: MoveId; message: () => string }>([ + { name: "Splash", move: MoveId.SPLASH, message: () => i18next.t("moveTriggers:splash") }, + { + name: "Celebrate", + move: MoveId.CELEBRATE, + message: () => i18next.t("moveTriggers:celebrate", { playerName: loggedInUser?.username }), + }, +])("Move - $name", ({ move, message }) => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .ability(AbilityId.BALL_FETCH) + .battleStyle("single") + .criticalHits(false) + .enemySpecies(SpeciesId.MAGIKARP) + .enemyAbility(AbilityId.BALL_FETCH) + .enemyMoveset(MoveId.TACKLE) + .startingLevel(100) + .enemyLevel(100); + }); + + it("should show a message on use", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); + + game.move.use(move); + await game.toEndOfTurn(); + + expect(game).toHaveShownMessage(message()); + }); +}); diff --git a/test/moves/wish.test.ts b/test/moves/wish.test.ts index 55877edbfd4..1c1f3f3b8ba 100644 --- a/test/moves/wish.test.ts +++ b/test/moves/wish.test.ts @@ -55,7 +55,7 @@ describe("Move - Wish", () => { await game.toEndOfTurn(); expect(game).toHavePositionalTag(PositionalTagType.WISH, 0); - expect(game.textInterceptor.logs).toContain( + expect(game).toHaveShownMessage( i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(alomomola), }), @@ -165,7 +165,7 @@ describe("Move - Wish", () => { // Wish went away without doing anything expect(game).toHavePositionalTag(PositionalTagType.WISH, 0); - expect(game.textInterceptor.logs).not.toContain( + expect(game).not.toHaveShownMessage( i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(blissey), }), diff --git a/test/mystery-encounter/encounter-test-utils.ts b/test/mystery-encounter/encounter-test-utils.ts index fcf27b2c6fb..7b2dbfc9aeb 100644 --- a/test/mystery-encounter/encounter-test-utils.ts +++ b/test/mystery-encounter/encounter-test-utils.ts @@ -13,10 +13,10 @@ import { } from "#phases/mystery-encounter-phases"; import { VictoryPhase } from "#phases/victory-phase"; import type { GameManager } from "#test/test-utils/game-manager"; -import type { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import type { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler"; -import type { PartyUiHandler } from "#ui/handlers/party-ui-handler"; +import type { MessageUiHandler } from "#ui/message-ui-handler"; +import type { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler"; import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; import { isNullOrUndefined } from "#utils/common"; import { expect, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts index 44585d4d795..5e9dffa1332 100644 --- a/test/mystery-encounter/encounters/berries-abound-encounter.test.ts +++ b/test/mystery-encounter/encounters/berries-abound-encounter.test.ts @@ -17,7 +17,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/berriesAbound"; diff --git a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts index a3357b00b89..723516174fb 100644 --- a/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts +++ b/test/mystery-encounter/encounters/bug-type-superfan-encounter.test.ts @@ -20,7 +20,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/bugTypeSuperfan"; diff --git a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts index d199a331943..e7ec6e43392 100644 --- a/test/mystery-encounter/encounters/clowning-around-encounter.test.ts +++ b/test/mystery-encounter/encounters/clowning-around-encounter.test.ts @@ -29,8 +29,8 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import type { PartyUiHandler } from "#ui/handlers/party-ui-handler"; import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts index bf42e6d4df3..81a2fc7463c 100644 --- a/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts +++ b/test/mystery-encounter/encounters/dancing-lessons-encounter.test.ts @@ -18,7 +18,7 @@ import { skipBattleRunMysteryEncounterRewardsPhase, } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/dancingLessons"; diff --git a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts index d6c566c4de6..c270429b394 100644 --- a/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts +++ b/test/mystery-encounter/encounters/department-store-sale-encounter.test.ts @@ -11,7 +11,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters"; import { CIVILIZATION_ENCOUNTER_BIOMES } from "#mystery-encounters/mystery-encounters"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/departmentStoreSale"; diff --git a/test/mystery-encounter/encounters/field-trip-encounter.test.ts b/test/mystery-encounter/encounters/field-trip-encounter.test.ts index b8e6e36cf17..fd3e20012b1 100644 --- a/test/mystery-encounter/encounters/field-trip-encounter.test.ts +++ b/test/mystery-encounter/encounters/field-trip-encounter.test.ts @@ -12,7 +12,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters"; import { SelectModifierPhase } from "#phases/select-modifier-phase"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import i18next from "i18next"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts index 34c0f635000..81dbad16e01 100644 --- a/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts +++ b/test/mystery-encounter/encounters/fight-or-flight-encounter.test.ts @@ -17,7 +17,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/fightOrFlight"; diff --git a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts index 8a058bad5fe..bc1a2893627 100644 --- a/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts +++ b/test/mystery-encounter/encounters/fun-and-games-encounter.test.ts @@ -22,7 +22,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/funAndGames"; diff --git a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts index 90bc41fde2b..c8e934168bc 100644 --- a/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts +++ b/test/mystery-encounter/encounters/global-trade-system-encounter.test.ts @@ -15,7 +15,7 @@ import * as MysteryEncounters from "#mystery-encounters/mystery-encounters"; import { CIVILIZATION_ENCOUNTER_BIOMES } from "#mystery-encounters/mystery-encounters"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import * as Utils from "#utils/common"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts index ed8b6bffbe9..a8d91f8f101 100644 --- a/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts +++ b/test/mystery-encounter/encounters/mysterious-challengers-encounter.test.ts @@ -20,7 +20,7 @@ import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; import { TrainerConfig } from "#trainers/trainer-config"; import { TrainerPartyCompoundTemplate, TrainerPartyTemplate } from "#trainers/trainer-party-template"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/mysteriousChallengers"; diff --git a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts index a096ea5ff6e..c88d77a8cf5 100644 --- a/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts +++ b/test/mystery-encounter/encounters/teleporting-hijinks-encounter.test.ts @@ -16,7 +16,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import i18next from "i18next"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts index 5df2d2ab358..06c4c3c1cee 100644 --- a/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts +++ b/test/mystery-encounter/encounters/the-strong-stuff-encounter.test.ts @@ -24,7 +24,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts index 9b009879522..814e2ee07fb 100644 --- a/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts +++ b/test/mystery-encounter/encounters/the-winstrate-challenge-encounter.test.ts @@ -20,7 +20,7 @@ import { VictoryPhase } from "#phases/victory-phase"; import { runMysteryEncounterToEnd } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts index 6f6c01c7322..91a88712e9b 100644 --- a/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts +++ b/test/mystery-encounter/encounters/trash-to-treasure-encounter.test.ts @@ -27,7 +27,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import * as Utils from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts index 3640ed3809f..f00ef834624 100644 --- a/test/mystery-encounter/encounters/weird-dream-encounter.test.ts +++ b/test/mystery-encounter/encounters/weird-dream-encounter.test.ts @@ -16,7 +16,7 @@ import { } from "#test/mystery-encounter/encounter-test-utils"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const namespace = "mysteryEncounters/weirdDream"; diff --git a/test/phases/mystery-encounter-phase.test.ts b/test/phases/mystery-encounter-phase.test.ts index 8dfbd509a05..30ab977dbc6 100644 --- a/test/phases/mystery-encounter-phase.test.ts +++ b/test/phases/mystery-encounter-phase.test.ts @@ -5,8 +5,8 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { MysteryEncounterOptionSelectedPhase } from "#phases/mystery-encounter-phases"; import { GameManager } from "#test/test-utils/game-manager"; -import type { MessageUiHandler } from "#ui/handlers/message-ui-handler"; -import type { MysteryEncounterUiHandler } from "#ui/handlers/mystery-encounter-ui-handler"; +import type { MessageUiHandler } from "#ui/message-ui-handler"; +import type { MysteryEncounterUiHandler } from "#ui/mystery-encounter-ui-handler"; import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/phases/select-modifier-phase.test.ts b/test/phases/select-modifier-phase.test.ts index f6446c6e7be..c6f07088819 100644 --- a/test/phases/select-modifier-phase.test.ts +++ b/test/phases/select-modifier-phase.test.ts @@ -12,7 +12,7 @@ import { ModifierTypeOption } from "#modifiers/modifier-type"; import { SelectModifierPhase } from "#phases/select-modifier-phase"; import { GameManager } from "#test/test-utils/game-manager"; import { initSceneWithoutEncounterPhase } from "#test/test-utils/game-manager-utils"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; import { shiftCharCodes } from "#utils/common"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import Phaser from "phaser"; diff --git a/test/plugins/api/pokerogue-daily-api.test.ts b/test/plugins/api/pokerogue-daily-api.test.ts index b45896e6a2c..ef5dfddada5 100644 --- a/test/plugins/api/pokerogue-daily-api.test.ts +++ b/test/plugins/api/pokerogue-daily-api.test.ts @@ -2,7 +2,7 @@ import { PokerogueDailyApi } from "#api/pokerogue-daily-api"; import { initServerForApiTests } from "#test/test-utils/test-file-initialization"; import { getApiBaseUrl } from "#test/test-utils/test-utils"; import type { GetDailyRankingsPageCountRequest, GetDailyRankingsRequest } from "#types/api/pokerogue-daily-api"; -import { type RankingEntry, ScoreboardCategory } from "#ui/containers/daily-run-scoreboard"; +import { type RankingEntry, ScoreboardCategory } from "#ui/daily-run-scoreboard"; import { HttpResponse, http } from "msw"; import type { SetupServerApi } from "msw/node"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/plugins/api/pokerogue-session-savedata-api.test.ts b/test/plugins/api/pokerogue-session-savedata-api.test.ts index d7ee2703405..d91db4425cb 100644 --- a/test/plugins/api/pokerogue-session-savedata-api.test.ts +++ b/test/plugins/api/pokerogue-session-savedata-api.test.ts @@ -1,5 +1,4 @@ import { PokerogueSessionSavedataApi } from "#api/pokerogue-session-savedata-api"; -import type { SessionSaveData } from "#system/game-data"; import { initServerForApiTests } from "#test/test-utils/test-file-initialization"; import { getApiBaseUrl } from "#test/test-utils/test-utils"; import type { @@ -10,6 +9,7 @@ import type { NewClearSessionSavedataRequest, UpdateSessionSavedataRequest, } from "#types/api/pokerogue-session-save-data-api"; +import type { SessionSaveData } from "#types/save-data"; import { HttpResponse, http } from "msw"; import type { SetupServerApi } from "msw/node"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/plugins/api/pokerogue-system-savedata-api.test.ts b/test/plugins/api/pokerogue-system-savedata-api.test.ts index d6e4fe18eed..3480b00b206 100644 --- a/test/plugins/api/pokerogue-system-savedata-api.test.ts +++ b/test/plugins/api/pokerogue-system-savedata-api.test.ts @@ -1,5 +1,4 @@ import { PokerogueSystemSavedataApi } from "#api/pokerogue-system-savedata-api"; -import type { SystemSaveData } from "#system/game-data"; import { initServerForApiTests } from "#test/test-utils/test-file-initialization"; import { getApiBaseUrl } from "#test/test-utils/test-utils"; import type { @@ -8,6 +7,7 @@ import type { VerifySystemSavedataRequest, VerifySystemSavedataResponse, } from "#types/api/pokerogue-system-save-data-api"; +import type { SystemSaveData } from "#types/save-data"; import { HttpResponse, http } from "msw"; import type { SetupServerApi } from "msw/node"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/font-face.setup.ts b/test/setup/font-face.setup.ts similarity index 100% rename from test/font-face.setup.ts rename to test/setup/font-face.setup.ts diff --git a/test/matchers.setup.ts b/test/setup/matchers.setup.ts similarity index 90% rename from test/matchers.setup.ts rename to test/setup/matchers.setup.ts index fe2135f4db4..88ca0a5c6bc 100644 --- a/test/matchers.setup.ts +++ b/test/setup/matchers.setup.ts @@ -8,6 +8,7 @@ import { toHaveFainted } from "#test/test-utils/matchers/to-have-fainted"; import { toHaveFullHp } from "#test/test-utils/matchers/to-have-full-hp"; import { toHaveHp } from "#test/test-utils/matchers/to-have-hp"; import { toHavePositionalTag } from "#test/test-utils/matchers/to-have-positional-tag"; +import { toHaveShownMessage } from "#test/test-utils/matchers/to-have-shown-message"; import { toHaveStatStage } from "#test/test-utils/matchers/to-have-stat-stage"; import { toHaveStatusEffect } from "#test/test-utils/matchers/to-have-status-effect"; import { toHaveTakenDamage } from "#test/test-utils/matchers/to-have-taken-damage"; @@ -20,11 +21,12 @@ import { expect } from "vitest"; /* * Setup file for custom matchers. - * Make sure to define the call signatures in `test/@types/vitest.d.ts` too! + * Make sure to define the call signatures in `#test/@types/vitest.d.ts` too! */ expect.extend({ toEqualArrayUnsorted, + toHaveShownMessage, toBeAtPhase, toHaveWeather, toHaveTerrain, diff --git a/test/vitest.setup.ts b/test/setup/vitest.setup.ts similarity index 93% rename from test/vitest.setup.ts rename to test/setup/vitest.setup.ts index 23adab01a05..3f506d73228 100644 --- a/test/vitest.setup.ts +++ b/test/setup/vitest.setup.ts @@ -35,8 +35,8 @@ vi.mock(import("i18next"), async importOriginal => { const filename = req.params[0]; try { - const localeFiles = import.meta.glob("../public/locales/en/**/*.json", { eager: true }); - const json = localeFiles[`../public/locales/en/${filename}`] || {}; + const localeFiles = import.meta.glob("../../public/locales/en/**/*.json", { eager: true }); + const json = localeFiles[`../../public/locales/en/${filename}`] || {}; if (import.meta.env.VITE_I18N_DEBUG === "1") { console.log("Loaded locale", filename); } diff --git a/test/system/game-data.test.ts b/test/system/game-data.test.ts index 18775f310b7..42a3ac339ce 100644 --- a/test/system/game-data.test.ts +++ b/test/system/game-data.test.ts @@ -3,8 +3,8 @@ import * as account from "#app/account"; import * as bypassLoginModule from "#app/global-vars/bypass-login"; import { AbilityId } from "#enums/ability-id"; import { MoveId } from "#enums/move-id"; -import type { SessionSaveData } from "#system/game-data"; import { GameManager } from "#test/test-utils/game-manager"; +import type { SessionSaveData } from "#types/save-data"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/system/rename-run.test.ts b/test/system/rename-run.test.ts index 5031d84245f..038303c3254 100644 --- a/test/system/rename-run.test.ts +++ b/test/system/rename-run.test.ts @@ -1,10 +1,10 @@ import * as account from "#app/account"; import * as bypassLoginModule from "#app/global-vars/bypass-login"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; -import type { SessionSaveData } from "#app/system/game-data"; import { AbilityId } from "#enums/ability-id"; import { MoveId } from "#enums/move-id"; import { GameManager } from "#test/test-utils/game-manager"; +import type { SessionSaveData } from "#types/save-data"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/test-utils/game-manager-utils.ts b/test/test-utils/game-manager-utils.ts index e9c3e9809cc..26b7ccf1020 100644 --- a/test/test-utils/game-manager-utils.ts +++ b/test/test-utils/game-manager-utils.ts @@ -8,8 +8,8 @@ import { GameModes } from "#enums/game-modes"; import type { MoveId } from "#enums/move-id"; import type { SpeciesId } from "#enums/species-id"; import { PlayerPokemon } from "#field/pokemon"; -import type { StarterMoveset } from "#system/game-data"; -import type { Starter } from "#ui/handlers/starter-select-ui-handler"; +import type { StarterMoveset } from "#types/save-data"; +import type { Starter } from "#ui/starter-select-ui-handler"; import { getPokemonSpecies, getPokemonSpeciesForm } from "#utils/pokemon-utils"; /** Function to convert Blob to string */ diff --git a/test/test-utils/game-manager.ts b/test/test-utils/game-manager.ts index bd2cdd80f68..0fb81f269e5 100644 --- a/test/test-utils/game-manager.ts +++ b/test/test-utils/game-manager.ts @@ -45,13 +45,13 @@ import { MockFetch } from "#test/test-utils/mocks/mock-fetch"; import { PhaseInterceptor } from "#test/test-utils/phase-interceptor"; import { TextInterceptor } from "#test/test-utils/text-interceptor"; import type { PhaseClass, PhaseString } from "#types/phase-types"; -import type { BallUiHandler } from "#ui/handlers/ball-ui-handler"; -import type { BattleMessageUiHandler } from "#ui/handlers/battle-message-ui-handler"; -import type { CommandUiHandler } from "#ui/handlers/command-ui-handler"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; -import type { PartyUiHandler } from "#ui/handlers/party-ui-handler"; -import type { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler"; -import type { TargetSelectUiHandler } from "#ui/handlers/target-select-ui-handler"; +import type { BallUiHandler } from "#ui/ball-ui-handler"; +import type { BattleMessageUiHandler } from "#ui/battle-message-ui-handler"; +import type { CommandUiHandler } from "#ui/command-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import type { PartyUiHandler } from "#ui/party-ui-handler"; +import type { StarterSelectUiHandler } from "#ui/starter-select-ui-handler"; +import type { TargetSelectUiHandler } from "#ui/target-select-ui-handler"; import { isNullOrUndefined } from "#utils/common"; import fs from "node:fs"; import { AES, enc } from "crypto-js"; diff --git a/test/test-utils/game-wrapper.ts b/test/test-utils/game-wrapper.ts index 166f4b8de7a..d18ea9301ea 100644 --- a/test/test-utils/game-wrapper.ts +++ b/test/test-utils/game-wrapper.ts @@ -12,7 +12,7 @@ import { MockLoader } from "#test/test-utils/mocks/mock-loader"; import { MockTextureManager } from "#test/test-utils/mocks/mock-texture-manager"; import { MockTimedEventManager } from "#test/test-utils/mocks/mock-timed-event-manager"; import { MockContainer } from "#test/test-utils/mocks/mocks-container/mock-container"; -import { PokedexMonContainer } from "#ui/containers/pokedex-mon-container"; +import { PokedexMonContainer } from "#ui/pokedex-mon-container"; import fs from "node:fs"; import Phaser from "phaser"; import { vi } from "vitest"; diff --git a/test/test-utils/helpers/daily-mode-helper.ts b/test/test-utils/helpers/daily-mode-helper.ts index 365c5df3627..ca882eaf548 100644 --- a/test/test-utils/helpers/daily-mode-helper.ts +++ b/test/test-utils/helpers/daily-mode-helper.ts @@ -7,7 +7,7 @@ import { EncounterPhase } from "#phases/encounter-phase"; import { TitlePhase } from "#phases/title-phase"; import { TurnInitPhase } from "#phases/turn-init-phase"; import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"; -import type { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler"; +import type { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler"; /** * Helper to handle daily mode specifics diff --git a/test/test-utils/helpers/overrides-helper.ts b/test/test-utils/helpers/overrides-helper.ts index 07ea1ea3d09..da0d75bf564 100644 --- a/test/test-utils/helpers/overrides-helper.ts +++ b/test/test-utils/helpers/overrides-helper.ts @@ -51,7 +51,8 @@ export class OverridesHelper extends GameManagerHelper { /** * Override the starting biome - * @warning Any event listeners that are attached to {@linkcode NewArenaEvent} may need to be handled down the line + * + * ⚠️ Any event listeners that are attached to {@linkcode NewArenaEvent} may need to be handled down the line * @param biome - The biome to set */ public startingBiome(biome: BiomeId): this { @@ -341,7 +342,11 @@ export class OverridesHelper extends GameManagerHelper { /** * Force random critical hit rolls to always or never suceed. * @param crits - `true` to guarantee crits on eligible moves, `false` to force rolls to fail, `null` to disable override - * @remarks This does not bypass effects that guarantee or block critical hits; it merely mocks the chance-based rolls. + * @remarks + * This does not change any effects that guarantee or block critical hits; + * it merely mocks any chance-based rolls not already at 100%. \ + * For instance, a Pokemon at +3 crit stages will still critically hit with the override set to `false`, + * whereas one at +2 crit stages (a 50% chance) will not. * @returns `this` */ public criticalHits(crits: boolean | null): this { diff --git a/test/test-utils/helpers/reload-helper.ts b/test/test-utils/helpers/reload-helper.ts index fa627019483..e46096f3fab 100644 --- a/test/test-utils/helpers/reload-helper.ts +++ b/test/test-utils/helpers/reload-helper.ts @@ -3,9 +3,9 @@ import { UiMode } from "#enums/ui-mode"; import { CommandPhase } from "#phases/command-phase"; import { TitlePhase } from "#phases/title-phase"; import { TurnInitPhase } from "#phases/turn-init-phase"; -import type { SessionSaveData } from "#system/game-data"; import type { GameManager } from "#test/test-utils/game-manager"; import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"; +import type { SessionSaveData } from "#types/save-data"; import { vi } from "vitest"; /** diff --git a/test/test-utils/matchers/to-have-shown-message.ts b/test/test-utils/matchers/to-have-shown-message.ts new file mode 100644 index 00000000000..bf5576ee630 --- /dev/null +++ b/test/test-utils/matchers/to-have-shown-message.ts @@ -0,0 +1,43 @@ +// biome-ignore lint/correctness/noUnusedImports: TSDoc +import type { GameManager } from "#test/test-utils/game-manager"; +import { isGameManagerInstance, receivedStr } from "#test/test-utils/test-utils"; +import { truncateString } from "#utils/common"; +import type { MatcherState, SyncExpectationResult } from "@vitest/expect"; + +/** + * Matcher to check if the {@linkcode GameManager} has shown the given message at least once. + * @param received - The object to check. Should be the current {@linkcode GameManager}. + * @param expectedMessage - The expected message + * @returns The result of the matching + */ +export function toHaveShownMessage( + this: MatcherState, + received: unknown, + expectedMessage: string, +): SyncExpectationResult { + if (!isGameManagerInstance(received)) { + return { + pass: this.isNot, + message: () => `Expected to receive a GameManager, but got ${receivedStr(received)}!`, + }; + } + + if (!received.textInterceptor) { + return { + pass: this.isNot, + message: () => "Expected GameManager.TextInterceptor to be defined!", + }; + } + + // Pass if any of the matching tags meet our criteria + const pass = received.textInterceptor.logs.includes(expectedMessage); + return { + pass, + message: () => + pass + ? `Expected the GameManager to NOT have shown the message ${truncateString(expectedMessage, 30)}, but it did!` + : `Expected the GameManager to have shown the message ${truncateString(expectedMessage, 30)}, but it didn't!`, + expected: expectedMessage, + actual: received.textInterceptor.logs, + }; +} diff --git a/test/test-utils/phase-interceptor.ts b/test/test-utils/phase-interceptor.ts index 4ac5e1150e5..6c7b5bf3033 100644 --- a/test/test-utils/phase-interceptor.ts +++ b/test/test-utils/phase-interceptor.ts @@ -67,7 +67,7 @@ import { UnlockPhase } from "#phases/unlock-phase"; import { VictoryPhase } from "#phases/victory-phase"; import { ErrorInterceptor } from "#test/test-utils/error-interceptor"; import type { PhaseClass, PhaseString } from "#types/phase-types"; -import type { AwaitableUiHandler } from "#ui/handlers/awaitable-ui-handler"; +import type { AwaitableUiHandler } from "#ui/awaitable-ui-handler"; import { UI } from "#ui/ui"; export interface PromptHandler { @@ -111,8 +111,8 @@ export class PhaseInterceptor { private intervalRun: NodeJS.Timeout; private prompts: PromptHandler[]; private inProgress?: InProgressStub; - private originalSetMode: UI["setMode"]; - private originalSuperEnd: Phase["end"]; + private originalSetMode: typeof UI.prototype.setMode; + private originalSuperEnd: typeof Phase.prototype.end; /** * List of phases with their corresponding start methods. diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index b9e73c3e9da..fe8a8f3cf8a 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -68,7 +68,7 @@ function isObject(received: unknown): received is object { /** * Helper function to check if a given object is a {@linkcode Pokemon}. * @param received - The object to check - * @return Whether `received` is a {@linkcode Pokemon} instance. + * @returns Whether `received` is a {@linkcode Pokemon} instance. */ export function isPokemonInstance(received: unknown): received is Pokemon { return isObject(received) && received instanceof Pokemon; diff --git a/test/ui/item-manage-button.test.ts b/test/ui/item-manage-button.test.ts index b5c24776e7b..c28cd9e802e 100644 --- a/test/ui/item-manage-button.test.ts +++ b/test/ui/item-manage-button.test.ts @@ -5,8 +5,8 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import type { Pokemon } from "#field/pokemon"; import { GameManager } from "#test/test-utils/game-manager"; -import type { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; -import { type PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import type { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import { type PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/ui/pokedex.test.ts b/test/ui/pokedex.test.ts index 47463fa1aab..6b84b253260 100644 --- a/test/ui/pokedex.test.ts +++ b/test/ui/pokedex.test.ts @@ -6,11 +6,11 @@ import { DropDownColumn } from "#enums/drop-down-column"; import { PokemonType } from "#enums/pokemon-type"; import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; -import type { StarterAttributes } from "#system/game-data"; import { GameManager } from "#test/test-utils/game-manager"; -import { FilterTextRow } from "#ui/containers/filter-text"; -import { PokedexPageUiHandler } from "#ui/containers/pokedex-page-ui-handler"; -import { PokedexUiHandler } from "#ui/handlers/pokedex-ui-handler"; +import type { StarterAttributes } from "#types/save-data"; +import { FilterTextRow } from "#ui/filter-text"; +import { PokedexPageUiHandler } from "#ui/pokedex-page-ui-handler"; +import { PokedexUiHandler } from "#ui/pokedex-ui-handler"; import { getPokemonSpecies } from "#utils/pokemon-utils"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/test/ui/starter-select.test.ts b/test/ui/starter-select.test.ts index 2f575b72a5c..397f3d6086f 100644 --- a/test/ui/starter-select.test.ts +++ b/test/ui/starter-select.test.ts @@ -8,10 +8,10 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import type { TitlePhase } from "#phases/title-phase"; import { GameManager } from "#test/test-utils/game-manager"; -import type { OptionSelectItem } from "#ui/handlers/abstract-option-select-ui-handler"; -import type { SaveSlotSelectUiHandler } from "#ui/handlers/save-slot-select-ui-handler"; -import type { StarterSelectUiHandler } from "#ui/handlers/starter-select-ui-handler"; +import type { OptionSelectItem } from "#ui/abstract-option-select-ui-handler"; import type { OptionSelectUiHandler } from "#ui/option-select-ui-handler"; +import type { SaveSlotSelectUiHandler } from "#ui/save-slot-select-ui-handler"; +import type { StarterSelectUiHandler } from "#ui/starter-select-ui-handler"; import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/ui/transfer-item-options.test.ts b/test/ui/transfer-item-options.test.ts index 7e9c1b5e36b..901aa261f50 100644 --- a/test/ui/transfer-item-options.test.ts +++ b/test/ui/transfer-item-options.test.ts @@ -4,8 +4,8 @@ import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { GameManager } from "#test/test-utils/game-manager"; -import { type PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; -import type { RenameFormUiHandler } from "#ui/handlers/rename-form-ui-handler"; +import { type PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; +import type { RenameFormUiHandler } from "#ui/rename-form-ui-handler"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/ui/transfer-item.test.ts b/test/ui/transfer-item.test.ts index 67a21b0656d..c04c16623e3 100644 --- a/test/ui/transfer-item.test.ts +++ b/test/ui/transfer-item.test.ts @@ -4,8 +4,8 @@ import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { GameManager } from "#test/test-utils/game-manager"; -import { ModifierSelectUiHandler } from "#ui/handlers/modifier-select-ui-handler"; -import { PartyUiHandler, PartyUiMode } from "#ui/handlers/party-ui-handler"; +import { ModifierSelectUiHandler } from "#ui/modifier-select-ui-handler"; +import { PartyUiHandler, PartyUiMode } from "#ui/party-ui-handler"; import Phaser from "phaser"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index 56891e22c2a..b5fe0d9585a 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -4,7 +4,7 @@ import { SpeciesId } from "#enums/species-id"; import { UiMode } from "#enums/ui-mode"; import { GameManager } from "#test/test-utils/game-manager"; import type { MockText } from "#test/test-utils/mocks/mocks-container/mock-text"; -import { FightUiHandler } from "#ui/handlers/fight-ui-handler"; +import { FightUiHandler } from "#ui/fight-ui-handler"; import i18next from "i18next"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; diff --git a/tsconfig.json b/tsconfig.json index 7bf82eaaca0..131a0503ee3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -50,7 +50,14 @@ ], "#trainers/*": ["./src/data/trainers/*.ts"], "#types/*": ["./src/@types/helpers/*.ts", "./src/@types/*.ts", "./src/typings/phaser/*.ts"], - "#ui/*": ["./src/ui/battle-info/*.ts", "./src/ui/settings/*.ts", "./src/ui/*.ts"], + "#ui/*": [ + "./src/ui/battle-info/*.ts", + "./src/ui/containers/*.ts", + "./src/ui/handlers/*.ts", + "./src/ui/settings/*.ts", + "./src/ui/utils/*.ts", + "./src/ui/*.ts" + ], "#utils/*": ["./src/utils/*.ts"], "#data/*": ["./src/data/pokemon-forms/*.ts", "./src/data/pokemon/*.ts", "./src/data/*.ts"], "#test/*": ["./test/*.ts"], diff --git a/tsdoc.json b/tsdoc.json index 689f7a96c5c..c17030cdbe7 100644 --- a/tsdoc.json +++ b/tsdoc.json @@ -13,6 +13,10 @@ { "tagName": "@module", "syntaxKind": "modifier" + }, + { + "tagName": "@interface", + "syntaxKind": "modifier" } ] } diff --git a/typedoc.config.js b/typedoc.config.js index ef932a5d077..d9e880743ca 100644 --- a/typedoc.config.js +++ b/typedoc.config.js @@ -3,7 +3,7 @@ import { globSync } from "node:fs"; const dryRun = !!process.env.DRY_RUN?.match(/true/gi); /** - * @type {Partial} + * */ const config = { entryPoints: ["./src", "./test/test-utils"], @@ -15,6 +15,7 @@ const config = { "test/test-utils/setup", "test/test-utils/reporters", ], + excludePrivate: false, // Private members are useful in the docs for contributors excludeReferences: true, // prevent documenting re-exports requiredToBeDocumented: [ "Enum", @@ -42,7 +43,7 @@ const config = { readme: "./README.md", coverageLabel: "Documented", coverageSvgWidth: 120, // Increased from 104 baseline due to adding 2 extra letters - favicon: "./public/images/logo.png", + favicon: "./favicon.ico", theme: "typedoc-github-theme", customFooterHtml: "

Copyright Pagefault Games 2025

", customFooterHtmlDisableWrapper: true, @@ -61,4 +62,5 @@ if (!dryRun && process.env.REF_NAME) { }; } +// biome-ignore lint/style/noDefaultExport: required by TypeDoc export default config; diff --git a/vitest.config.ts b/vitest.config.ts index 7fa2494bb4e..682b8052878 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -15,7 +15,7 @@ export default defineConfig(({ mode }) => ({ slowTestThreshold: 10_000, // TODO: Consider enabling // expect: {requireAssertions: true}, - setupFiles: ["./test/font-face.setup.ts", "./test/vitest.setup.ts", "./test/matchers.setup.ts"], + setupFiles: ["./test/setup/font-face.setup.ts", "./test/setup/vitest.setup.ts", "./test/setup/matchers.setup.ts"], sequence: { sequencer: MySequencer, },