mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-24 00:09:31 +02:00
Merge branch 'beta' of https://github.com/pagefaultgames/pokerogue into feature/settings-noReloadRequire
This commit is contained in:
commit
17ce1162b7
@ -1,6 +1,6 @@
|
||||
VITE_BYPASS_LOGIN=0
|
||||
VITE_BYPASS_TUTORIAL=0
|
||||
VITE_SERVER_URL=https://api.beta.pokerogue.net
|
||||
VITE_SERVER_URL=https://apibeta.pokerogue.net
|
||||
VITE_DISCORD_CLIENT_ID=1248062921129459756
|
||||
VITE_GOOGLE_CLIENT_ID=955345393540-2k6lfftf0fdnb0krqmpthjnqavfvvf73.apps.googleusercontent.com
|
||||
VITE_I18N_DEBUG=1
|
||||
VITE_I18N_DEBUG=0
|
||||
|
@ -3,5 +3,5 @@ VITE_BYPASS_TUTORIAL=0
|
||||
VITE_SERVER_URL=http://localhost:8001
|
||||
VITE_DISCORD_CLIENT_ID=1234567890
|
||||
VITE_GOOGLE_CLIENT_ID=1234567890
|
||||
VITE_I18N_DEBUG=1
|
||||
VITE_I18N_DEBUG=0
|
||||
VITE_PORT=8000
|
||||
|
7
.github/CODEOWNERS
vendored
Normal file
7
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# Order is important; the last matching pattern takes the most precedence.
|
||||
|
||||
# everything (whole code-base) - Junior Devs
|
||||
* @pagefaultgames/junior-dev-team
|
||||
|
||||
# github actions/templates etc. - Dev Leads
|
||||
/.github @pagefaultgames/dev-leads
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: pagefaultgames
|
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,7 +1,7 @@
|
||||
name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
title: "[Bug] "
|
||||
labels: ["Bug"]
|
||||
labels: ["Bug", "Triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@ -19,21 +19,12 @@ body:
|
||||
value: |
|
||||
---
|
||||
- type: textarea
|
||||
id: session-file
|
||||
id: repro
|
||||
attributes:
|
||||
label: Session export file
|
||||
description: Open Menu → ManageData → Export Session → Select slot. The file should now be in your `/Downloads` directory. Change the file extension type from `.prsv` to `.txt` (How to [Windows](https://www.guidingtech.com/how-to-change-file-type-on-windows/) | [Mac](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) | [iOS](https://www.guidingtech.com/change-file-type-extension-on-iphone/)).
|
||||
placeholder: Focus me and then drop your file here (or use the upload button at the bottom)
|
||||
label: Reproduction
|
||||
description: Describe the steps to reproduce this bug. If applicable attach user/session data at the bottom
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: data-file
|
||||
attributes:
|
||||
label: User data export file
|
||||
description: Open Menu → ManageData → Export Data. The file should now be in your `/Downloads` directory. Change the file extension type from `.prsv` to `.txt` (How to [Windows](https://www.guidingtech.com/how-to-change-file-type-on-windows/) | [Mac](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) | [iOS](https://www.guidingtech.com/change-file-type-extension-on-iphone/)).
|
||||
placeholder: Focus me and then drop your file here (or use the upload button at the bottom)
|
||||
validations:
|
||||
required: false
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
@ -60,48 +51,20 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
---
|
||||
- type: dropdown
|
||||
id: os
|
||||
- type: textarea
|
||||
id: session-file
|
||||
attributes:
|
||||
label: What OS did you observe the bug on?
|
||||
multiple: true
|
||||
options:
|
||||
- PC/Windows
|
||||
- Mac/OSX
|
||||
- Linux
|
||||
- iOS
|
||||
- Android
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os-other
|
||||
attributes:
|
||||
label: If other please specify
|
||||
label: Session export file
|
||||
description: Open Menu → ManageData → Export Session → Select slot. The file should now be in your `/Downloads` directory. Change the file extension type from `.prsv` to `.txt` (How to [Windows](https://www.guidingtech.com/how-to-change-file-type-on-windows/) | [Mac](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) | [iOS](https://www.guidingtech.com/change-file-type-extension-on-iphone/)).
|
||||
placeholder: Focus me and then drop your file here (or use the upload button at the bottom)
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
- type: textarea
|
||||
id: data-file
|
||||
attributes:
|
||||
value: |
|
||||
---
|
||||
- type: dropdown
|
||||
id: browser
|
||||
attributes:
|
||||
label: Which browser do you use?
|
||||
multiple: true
|
||||
options:
|
||||
- Chrome
|
||||
- Firefox
|
||||
- Safari
|
||||
- Edge
|
||||
- Opera
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: browser-other
|
||||
attributes:
|
||||
label: If other please specify
|
||||
label: User data export file
|
||||
description: Open Menu → ManageData → Export Data. The file should now be in your `/Downloads` directory. Change the file extension type from `.prsv` to `.txt` (How to [Windows](https://www.guidingtech.com/how-to-change-file-type-on-windows/) | [Mac](https://support.apple.com/guide/mac-help/show-or-hide-filename-extensions-on-mac-mchlp2304/mac) | [iOS](https://www.guidingtech.com/change-file-type-extension-on-iphone/)).
|
||||
placeholder: Focus me and then drop your file here (or use the upload button at the bottom)
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,7 +1,7 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
title: "[Feature] "
|
||||
labels: ["enhancement"]
|
||||
labels: ["Enhancement", "Triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -30,7 +30,7 @@
|
||||
- [ ] The PR is self-contained and cannot be split into smaller PRs?
|
||||
- [ ] Have I provided a clear explanation of the changes?
|
||||
- [ ] Have I considered writing automated tests for the issue?
|
||||
- [ ] If I have text, did I add placeholders for them in locales?
|
||||
- [ ] If I have text, did I make it translatable and add a key in the English locale file(s)?
|
||||
- [ ] Have I tested the changes (manually)?
|
||||
- [ ] Are all unit tests still passing? (`npm run test`)
|
||||
- [ ] Are the changes visual?
|
||||
|
2
.github/workflows/deploy-beta.yml
vendored
2
.github/workflows/deploy-beta.yml
vendored
@ -11,6 +11,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
18
.github/workflows/deploy.yml
vendored
18
.github/workflows/deploy.yml
vendored
@ -1,8 +1,12 @@
|
||||
name: Deploy
|
||||
name: Deploy Main
|
||||
|
||||
on:
|
||||
push: {}
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
@ -10,6 +14,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
@ -20,7 +26,7 @@ jobs:
|
||||
env:
|
||||
NODE_ENV: production
|
||||
- name: Set up SSH
|
||||
if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
if: github.event_name == 'push' && github.ref_name == 'main'
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SSH_PUBLIC_KEY }}" > ~/.ssh/id_ed25519.pub
|
||||
@ -28,12 +34,12 @@ jobs:
|
||||
chmod 600 ~/.ssh/*
|
||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
||||
- name: Deploy build on server
|
||||
if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
if: github.event_name == 'push' && github.ref_name == 'main'
|
||||
run: |
|
||||
rsync --del --no-times --checksum -vrm dist/* ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DESTINATION_DIR }}
|
||||
ssh -t ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "~/prmanifest --inpath ${{ secrets.DESTINATION_DIR }} --outpath ${{ secrets.DESTINATION_DIR }}/manifest.json"
|
||||
- name: Purge Cloudflare Cache
|
||||
if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
|
||||
if: github.event_name == 'push' && github.ref_name == 'main'
|
||||
id: purge-cache
|
||||
uses: NathanVaughn/actions-cloudflare-purge@v3.1.0
|
||||
with:
|
||||
|
10
.github/workflows/eslint.yml
vendored
10
.github/workflows/eslint.yml
vendored
@ -11,6 +11,8 @@ on:
|
||||
branches:
|
||||
- main # Trigger on pull request events targeting the main branch
|
||||
- beta # Trigger on pull request events targeting the beta branch
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
|
||||
jobs:
|
||||
run-linters: # Define a job named "run-linters"
|
||||
@ -19,10 +21,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository # Step to check out the repository
|
||||
uses: actions/checkout@v2 # Use the checkout action version 2
|
||||
uses: actions/checkout@v4 # Use the checkout action version 4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Set up Node.js # Step to set up Node.js environment
|
||||
uses: actions/setup-node@v1 # Use the setup-node action version 1
|
||||
uses: actions/setup-node@v4 # Use the setup-node action version 4
|
||||
with:
|
||||
node-version: 20 # Specify Node.js version 20
|
||||
|
||||
@ -30,4 +34,4 @@ jobs:
|
||||
run: npm ci # Use 'npm ci' to install dependencies
|
||||
|
||||
- name: eslint # Step to run linters
|
||||
run: npm run eslint-ci
|
||||
run: npm run eslint-ci
|
||||
|
3
.github/workflows/github-pages.yml
vendored
3
.github/workflows/github-pages.yml
vendored
@ -8,6 +8,8 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- beta
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
|
||||
jobs:
|
||||
pages:
|
||||
@ -24,6 +26,7 @@ jobs:
|
||||
- name: Checkout repository for Typedoc
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
path: pokerogue_docs
|
||||
|
||||
- name: Install OS package
|
||||
|
32
.github/workflows/test-shard-template.yml
vendored
Normal file
32
.github/workflows/test-shard-template.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Test Template
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
project:
|
||||
required: true
|
||||
type: string
|
||||
shard:
|
||||
required: true
|
||||
type: number
|
||||
totalShards:
|
||||
required: true
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Shard ${{ inputs.shard }} of ${{ inputs.totalShards }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
run: npm ci
|
||||
- name: Run tests
|
||||
run: npx vitest --project ${{ inputs.project }} --shard=${{ inputs.shard }}/${{ inputs.totalShards }} ${{ !runner.debug && '--silent' || '' }}
|
45
.github/workflows/tests.yml
vendored
45
.github/workflows/tests.yml
vendored
@ -11,23 +11,38 @@ on:
|
||||
branches:
|
||||
- main # Trigger on pull request events targeting the main branch
|
||||
- beta # Trigger on pull request events targeting the beta branch
|
||||
merge_group:
|
||||
types: [checks_requested]
|
||||
|
||||
jobs:
|
||||
run-tests: # Define a job named "run-tests"
|
||||
name: Run tests # Human-readable name for the job
|
||||
runs-on: ubuntu-latest # Specify the latest Ubuntu runner for the job
|
||||
|
||||
pre-test:
|
||||
name: Run Pre-test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out Git repository # Step to check out the repository
|
||||
uses: actions/checkout@v4 # Use the checkout action version 4
|
||||
|
||||
- name: Set up Node.js # Step to set up Node.js environment
|
||||
uses: actions/setup-node@v4 # Use the setup-node action version 4
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
node-version: 20 # Specify Node.js version 20
|
||||
submodules: 'recursive'
|
||||
path: tests-action
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
working-directory: tests-action
|
||||
run: npm ci
|
||||
- name: Run Pre-test
|
||||
working-directory: tests-action
|
||||
run: npx vitest run --project pre ${{ !runner.debug && '--silent' || '' }}
|
||||
|
||||
- name: Install Node.js dependencies # Step to install Node.js dependencies
|
||||
run: npm ci # Use 'npm ci' to install dependencies
|
||||
|
||||
- name: tests # Step to run tests
|
||||
run: npm run test:silent
|
||||
run-tests:
|
||||
name: Run Tests
|
||||
needs: [pre-test]
|
||||
strategy:
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
uses: ./.github/workflows/test-shard-template.yml
|
||||
with:
|
||||
project: main
|
||||
shard: ${{ matrix.shard }}
|
||||
totalShards: 10
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "public/locales"]
|
||||
path = public/locales
|
||||
url = https://github.com/pagefaultgames/pokerogue-locales
|
15
README.md
15
README.md
@ -17,13 +17,21 @@ If you have the motivation and experience with Typescript/Javascript (or are wil
|
||||
2. Run `npm run start:dev` to locally run the project in `localhost:8000`
|
||||
|
||||
#### Linting
|
||||
We're using ESLint as our common linter and formatter. It will run automatically during the pre-commit hook but if you would like to manually run it, use the `npm run eslint` script.
|
||||
We're using ESLint as our common linter and formatter. It will run automatically during the pre-commit hook but if you would like to manually run it, use the `npm run eslint` script. To view the complete rules, check out the [eslint.config.js](./eslint.config.js) file.
|
||||
|
||||
### 📚 Documentation
|
||||
You can find the auto-generated documentation [here](https://pagefaultgames.github.io/pokerogue/main/index.html).
|
||||
For information on enemy AI, check out the [enemy-ai.md](./docs/enemy-ai.md) file.
|
||||
For detailed guidelines on documenting your code, refer to the [comments.md](./docs/comments.md) file.
|
||||
|
||||
### ❔ FAQ
|
||||
|
||||
**How do I test a new _______?**
|
||||
- In the `src/overrides.ts` file there are overrides for most values you'll need to change for testing
|
||||
|
||||
**How do I retrieve the translations?**
|
||||
- The translations were moved to the [dedicated translation repository](https://github.com/pagefaultgames/pokerogue-locales) and are now applied as a submodule in this project.
|
||||
- The command to retrieve the translations is `git submodule update --init --recursive`. If you still struggle to get it working, please reach out to #dev-corner channel in Discord.
|
||||
|
||||
## 🪧 To Do
|
||||
Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to see how can you help us!
|
||||
@ -53,9 +61,10 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to
|
||||
- Pokémon Sun/Moon
|
||||
- Pokémon Ultra Sun/Ultra Moon
|
||||
- Pokémon Sword/Shield
|
||||
- Pokémon Legends: Arceus
|
||||
- Pokémon Scarlet/Violet
|
||||
- Firel (Custom Laboratory, Metropolis, Seabed, and Space biome music)
|
||||
- Lmz (Custom Jungle biome music)
|
||||
- Firel (Custom Ice Cave, Laboratory, Metropolis, Plains, Power Plant, Seabed, Space, and Volcano biome music)
|
||||
- Lmz (Custom Ancient Ruins, Jungle, and Lake biome music)
|
||||
- Andr06 (Custom Slum and Sea biome music)
|
||||
|
||||
### 🎵 Sound Effects
|
||||
|
171
create-test-boilerplate.js
Normal file
171
create-test-boilerplate.js
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* This script creates a test boilerplate file in the appropriate
|
||||
* directory based on the type selected.
|
||||
* @example npm run create-test
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import inquirer from "inquirer";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// Get the directory name of the current module file
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const typeChoices = ["Move", "Ability", "Item", "Mystery Encounter"];
|
||||
|
||||
/**
|
||||
* Prompts the user to select a type via list.
|
||||
* @returns {Promise<{selectedOption: string}>} the selected type
|
||||
*/
|
||||
async function promptTestType() {
|
||||
const typeAnswer = await inquirer.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "selectedOption",
|
||||
message: "What type of test would you like to create:",
|
||||
choices: [...typeChoices, "EXIT"],
|
||||
},
|
||||
]);
|
||||
|
||||
if (typeAnswer.selectedOption === "EXIT") {
|
||||
console.log("Exiting...");
|
||||
return process.exit();
|
||||
} else if (!typeChoices.includes(typeAnswer.selectedOption)) {
|
||||
console.error(`Please provide a valid type (${typeChoices.join(", ")})!`);
|
||||
return await promptTestType();
|
||||
}
|
||||
|
||||
return typeAnswer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user to provide a file name.
|
||||
* @param {string} selectedType
|
||||
* @returns {Promise<{userInput: string}>} the selected file name
|
||||
*/
|
||||
async function promptFileName(selectedType) {
|
||||
const fileNameAnswer = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "userInput",
|
||||
message: `Please provide the name of the ${selectedType}:`,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!fileNameAnswer.userInput || fileNameAnswer.userInput.trim().length === 0) {
|
||||
console.error("Please provide a valid file name!");
|
||||
return await promptFileName(selectedType);
|
||||
}
|
||||
|
||||
return fileNameAnswer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the interactive create-test "CLI"
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function runInteractive() {
|
||||
const typeAnswer = await promptTestType();
|
||||
const fileNameAnswer = await promptFileName(typeAnswer.selectedOption);
|
||||
|
||||
const type = typeAnswer.selectedOption.toLowerCase();
|
||||
// Convert fileName from kebab-case or camelCase to snake_case
|
||||
const fileName = fileNameAnswer.userInput
|
||||
.replace(/-+/g, "_") // Convert kebab-case (dashes) to underscores
|
||||
.replace(/([a-z])([A-Z])/g, "$1_$2") // Convert camelCase to snake_case
|
||||
.replace(/\s+/g, '_') // Replace spaces with underscores
|
||||
.toLowerCase(); // Ensure all lowercase
|
||||
// Format the description for the test case
|
||||
|
||||
const formattedName = fileName.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
||||
// Determine the directory based on the type
|
||||
let dir;
|
||||
let description;
|
||||
switch (type) {
|
||||
case "move":
|
||||
dir = path.join(__dirname, "src", "test", "moves");
|
||||
description = `Moves - ${formattedName}`;
|
||||
break;
|
||||
case "ability":
|
||||
dir = path.join(__dirname, "src", "test", "abilities");
|
||||
description = `Abilities - ${formattedName}`;
|
||||
break;
|
||||
case "item":
|
||||
dir = path.join(__dirname, "src", "test", "items");
|
||||
description = `Items - ${formattedName}`;
|
||||
break;
|
||||
case "mystery encounter":
|
||||
dir = path.join(__dirname, "src", "test", "mystery-encounter", "encounters");
|
||||
description = `Mystery Encounter - ${formattedName}`;
|
||||
break;
|
||||
default:
|
||||
console.error(`Invalid type. Please use one of the following: ${typeChoices.join(", ")}.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Define the content template
|
||||
const content = `import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("${description}", () => {
|
||||
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
|
||||
.moveset([ Moves.SPLASH ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("should do X", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
`;
|
||||
|
||||
// Ensure the directory exists
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create the file with the given name
|
||||
const filePath = path.join(dir, `${fileName}.test.ts`);
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
console.error(`File "${fileName}.test.ts" already exists.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Write the template content to the file
|
||||
fs.writeFileSync(filePath, content, "utf8");
|
||||
|
||||
console.log(`File created at: ${filePath}`);
|
||||
}
|
||||
|
||||
runInteractive();
|
@ -191,15 +191,15 @@ Now that the enemy Pokémon with the best matchup score is on the field (assumin
|
||||
|
||||
We then need to apply a 2x multiplier for the move's type effectiveness and a 1.5x multiplier since STAB applies. After applying these multipliers, the final score for this move is **75**.
|
||||
|
||||
- **Swords Dance**: As a non-attacking move, this move's benefit score is derived entirely from the sum of its attributes' benefit scores. Swords Dance's `StatChangeAttr` has a user benefit score of 0 and a target benefit score that, in this case, simplifies to
|
||||
- **Swords Dance**: As a non-attacking move, this move's benefit score is derived entirely from the sum of its attributes' benefit scores. Swords Dance's `StatStageChangeAttr` has a user benefit score of 0 and a target benefit score that, in this case, simplifies to
|
||||
|
||||
$\text{TBS}=4\times \text{levels} + (-2\times \text{sign(levels)})$
|
||||
|
||||
where `levels` is the number of stat stages added by the attribute (in this case, +2). The final score for this move is **6** (Note: because this move is self-targeted, we don't flip the sign of TBS when computing the target score).
|
||||
|
||||
- **Crush Claw**: This move is a 75-power Normal-type physical attack with a 50 percent chance to lower the target's Defense by one stage. The additional effect is implemented by the same `StatChangeAttr` as Swords Dance, so we can use the same formulas from before to compute the total TBS and base target score.
|
||||
- **Crush Claw**: This move is a 75-power Normal-type physical attack with a 50 percent chance to lower the target's Defense by one stage. The additional effect is implemented by the same `StatStageChangeAttr` as Swords Dance, so we can use the same formulas from before to compute the total TBS and base target score.
|
||||
|
||||
$\text{TBS}=\text{getTargetBenefitScore(StatChangeAttr)}-\text{attackScore}$
|
||||
$\text{TBS}=\text{getTargetBenefitScore(StatStageChangeAttr)}-\text{attackScore}$
|
||||
|
||||
$\text{TBS}=(-4 + 2)-(-2\times 2 + \lfloor \frac{75}{5} \rfloor)=-2-11=-13$
|
||||
|
||||
@ -221,4 +221,4 @@ When implementing a new move attribute, it's important to override `MoveAttr`'s
|
||||
- A move's **user benefit score (UBS)** incentivizes (or discourages) the move's usage in general. A positive UBS gives the move more incentive to be used, while a negative UBS gives the move less incentive.
|
||||
- A move's **target benefit score (TBS)** incentivizes (or discourages) the move's usage on a specific target. A positive TBS indicates the move is better used on the user or its allies, while a negative TBS indicates the move is better used on enemies.
|
||||
- **The total benefit score (UBS + TBS) of a move should never be 0.** The move selection algorithm assumes the move's benefit score is unimplemented if the total score is 0 and penalizes the move's usage as a result. With status moves especially, it's important to have some form of implementation among the move's attributes to avoid this scenario.
|
||||
- **Score functions that use formulas should include comments.** If your attribute requires complex logic or formulas to calculate benefit scores, please add comments to explain how the logic works and its intended effect on the enemy's decision making.
|
||||
- **Score functions that use formulas should include comments.** If your attribute requires complex logic or formulas to calculate benefit scores, please add comments to explain how the logic works and its intended effect on the enemy's decision making.
|
||||
|
@ -1,7 +1,7 @@
|
||||
import tseslint from '@typescript-eslint/eslint-plugin';
|
||||
import stylisticTs from '@stylistic/eslint-plugin-ts'
|
||||
import parser from '@typescript-eslint/parser';
|
||||
// import imports from 'eslint-plugin-import'; // Disabled due to not being compatible with eslint v9
|
||||
import importX from 'eslint-plugin-import-x';
|
||||
|
||||
export default [
|
||||
{
|
||||
@ -11,7 +11,7 @@ export default [
|
||||
parser: parser
|
||||
},
|
||||
plugins: {
|
||||
// imports: imports.configs.recommended // Disabled due to not being compatible with eslint v9
|
||||
"import-x": importX,
|
||||
'@stylistic/ts': stylisticTs,
|
||||
'@typescript-eslint': tseslint
|
||||
},
|
||||
@ -38,7 +38,14 @@ export default [
|
||||
"ignoreComments": false // Enforces the rule on lines containing comments
|
||||
}],
|
||||
"space-before-blocks": ["error", "always"], // Enforces a space before blocks
|
||||
"keyword-spacing": ["error", { "before": true, "after": true }] // Enforces spacing before and after keywords
|
||||
"keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords
|
||||
"comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma
|
||||
"import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json
|
||||
"array-bracket-spacing": ["error", "always", { "objectsInArrays": false, "arraysInArrays": false }], // Enforces consistent spacing inside array brackets
|
||||
"object-curly-spacing": ["error", "always", { "arraysInObjects": false, "objectsInObjects": false }], // Enforces consistent spacing inside braces of object literals, destructuring assignments, and import/export specifiers
|
||||
"computed-property-spacing": ["error", "never" ], // Enforces consistent spacing inside computed property brackets
|
||||
"space-infix-ops": ["error", { "int32Hint": false }], // Enforces spacing around infix operators
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], // Disallows multiple empty lines
|
||||
}
|
||||
}
|
||||
]
|
||||
|
47
index.css
47
index.css
@ -17,22 +17,45 @@ body {
|
||||
background: #484050;
|
||||
}
|
||||
|
||||
#links {
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
@media (display-mode: fullscreen) {
|
||||
body {
|
||||
background: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#app > div:first-child {
|
||||
transform-origin: top !important;
|
||||
transform-origin: center !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Supports automatic vertical centering as suggested in PR#1114, but only via CSS
|
||||
|
||||
Condition factorized to deduce CSS rules:
|
||||
true if (isLandscape && !isMobile() && !hasTouchscreen() || (hasTouchscreen() && !isTouchControlsEnabled))
|
||||
*/
|
||||
|
||||
/* isLandscape && !isMobile() && !hasTouchscreen() */
|
||||
@media (orientation: landscape) and (pointer: fine) {
|
||||
#app {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
/* hasTouchscreen() && !isTouchControlsEnabled */
|
||||
body:has(> #touchControls[class=visible]) #app {
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
body:has(> #touchControls[class=visible]) #app > div:first-child {
|
||||
transform-origin: top !important;
|
||||
}
|
||||
}
|
||||
|
||||
#layout:fullscreen #dpad, #layout:fullscreen {
|
||||
@ -87,7 +110,7 @@ input:-internal-autofill-selected {
|
||||
|
||||
@media (orientation: landscape) {
|
||||
#touchControls {
|
||||
--controls-size: 20vh;
|
||||
--controls-size: 20vh;
|
||||
--text-shadow-size: 1.3vh;
|
||||
--small-button-offset: 4vh;
|
||||
}
|
||||
@ -142,10 +165,10 @@ input:-internal-autofill-selected {
|
||||
|
||||
/* Show cycle buttons only on STARTER_SELECT and on touch configuration panel */
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadOpenFilters,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleForm,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleShiny,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleForm,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleShiny,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleNature,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleAbility,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='RUN_INFO']) #apadCycleAbility,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleGender,
|
||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleVariant {
|
||||
display: none;
|
||||
|
@ -39,7 +39,6 @@
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="./index.css" />
|
||||
<link rel="manifest" href="./manifest.webmanifest">
|
||||
<script type="text/javascript" src="https://app.termly.io/resource-blocker/c5dbfa2f-9723-4c0f-a84b-2895124e851f?autoBlock=on"></script>
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", function () {
|
||||
@ -144,13 +143,6 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="tnc-links">
|
||||
<a href="#" class="termly-display-preferences" style="display: none;" target="_blank" rel="noreferrer noopener">Consent Preferences</a>
|
||||
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=bc96778b-3f04-4d25-bafc-0deba53e8bec" target="_blank" rel="noreferrer noopener">Privacy Policy</a>
|
||||
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=8b523c05-7ec2-4646-9534-5bd61b386e2a" target="_blank" rel="noreferrer noopener">Cookie Disclaimer</a>
|
||||
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=b01e092a-9721-477f-8356-45576702ff9e" target="_blank" rel="noreferrer noopener">Terms & Conditions</a>
|
||||
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=3b5d1928-3f5b-4ee1-b8df-2d6c276b0bcc" target="_blank" rel="noreferrer noopener">Acceptable Use Policy</a>
|
||||
</div>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
<script src="./src/touch-controls.ts" type="module"></script>
|
||||
<script src="./src/debug.js" type="module"></script>
|
||||
|
18
lefthook.yml
18
lefthook.yml
@ -2,6 +2,20 @@ pre-commit:
|
||||
parallel: true
|
||||
commands:
|
||||
eslint:
|
||||
glob: '*.{js,jsx,ts,tsx}'
|
||||
glob: "*.{js,jsx,ts,tsx}"
|
||||
run: npx eslint --fix {staged_files}
|
||||
stage_fixed: true
|
||||
stage_fixed: true
|
||||
skip:
|
||||
- merge
|
||||
- rebase
|
||||
|
||||
pre-push:
|
||||
commands:
|
||||
eslint:
|
||||
glob: "*.{js,ts,jsx,tsx}"
|
||||
run: npx eslint --fix {push_files}
|
||||
|
||||
post-merge:
|
||||
commands:
|
||||
update-submodules:
|
||||
run: git submodule update --init --recursive
|
1093
package-lock.json
generated
1093
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -18,7 +18,9 @@
|
||||
"eslint-ci": "eslint .",
|
||||
"docs": "typedoc",
|
||||
"depcruise": "depcruise src",
|
||||
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg"
|
||||
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
|
||||
"create-test": "node ./create-test-boilerplate.js",
|
||||
"postinstall": "npx lefthook install && npx lefthook run post-merge"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.3.0",
|
||||
@ -31,13 +33,16 @@
|
||||
"@vitest/coverage-istanbul": "^2.0.4",
|
||||
"dependency-cruiser": "^16.3.10",
|
||||
"eslint": "^9.7.0",
|
||||
"eslint-plugin-import-x": "^4.2.1",
|
||||
"inquirer": "^11.0.2",
|
||||
"jsdom": "^24.0.0",
|
||||
"lefthook": "^1.6.12",
|
||||
"msw": "^2.4.9",
|
||||
"phaser3spectorjs": "^0.0.8",
|
||||
"typedoc": "^0.26.4",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.0.0-alpha.54",
|
||||
"vite": "^5.3.5",
|
||||
"vite": "^5.4.8",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^2.0.4",
|
||||
"vitest-canvas-mock": "^0.3.3"
|
||||
@ -47,6 +52,7 @@
|
||||
"crypto-js": "^4.2.0",
|
||||
"i18next": "^23.11.1",
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"i18next-http-backend": "^2.6.1",
|
||||
"i18next-korean-postposition-processor": "^1.0.0",
|
||||
"json-stable-stringify": "^1.1.0",
|
||||
"phaser": "^3.70.0",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user