Merge branch 'beta' into disable_battlertag
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: "[Feature]"
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
|
||||||
|
|
||||||
**Describe the Feature**
|
|
||||||
<!-- A clear and concise description of what you want to happen. -->
|
|
||||||
<!-- Add a link to the feature if it is an existing move/ability/etc -->
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
<!-- Add any other context or screenshots about the feature request here. -->
|
|
39
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: Suggest an idea for this project
|
||||||
|
title: "[Feature] "
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this feature request!
|
||||||
|
- type: textarea
|
||||||
|
id: relation
|
||||||
|
attributes:
|
||||||
|
label: Is your feature request related to a problem? Please describe.
|
||||||
|
description: Clear and concise description of what the problem is.
|
||||||
|
placeholder: E.g. "I'm always frustrated when [...]"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
---
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Describe the Feature
|
||||||
|
description: A clear and concise description of what you want to happen. Add a link to the feature if it is an existing move/ability/etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
---
|
||||||
|
- type: textarea
|
||||||
|
id: additional-context
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context or screenshots about the feature request here.
|
||||||
|
validations:
|
||||||
|
required: true
|
5
.github/pull_request_template.md
vendored
@ -5,12 +5,12 @@
|
|||||||
## What are the changes?
|
## What are the changes?
|
||||||
<!-- Summarize what are the changes from a user perspective on the application -->
|
<!-- Summarize what are the changes from a user perspective on the application -->
|
||||||
|
|
||||||
## Why am I doing these changes?
|
## Why am I doing these changes the user will see?
|
||||||
<!-- Explain why you decided to introduce these changes -->
|
<!-- Explain why you decided to introduce these changes -->
|
||||||
<!-- Does it come from an issue or another PR? Please link it -->
|
<!-- Does it come from an issue or another PR? Please link it -->
|
||||||
<!-- Explain why you believe this can enhance user experience -->
|
<!-- Explain why you believe this can enhance user experience -->
|
||||||
|
|
||||||
## What did change?
|
## What are the changes from a developer perspective?
|
||||||
<!-- Explicitly state what are the changes introduced by the PR -->
|
<!-- Explicitly state what are the changes introduced by the PR -->
|
||||||
<!-- You can make use of a comparison between what was the state before and after your PR changes -->
|
<!-- You can make use of a comparison between what was the state before and after your PR changes -->
|
||||||
|
|
||||||
@ -30,6 +30,7 @@
|
|||||||
- [ ] The PR is self-contained and cannot be split into smaller PRs?
|
- [ ] The PR is self-contained and cannot be split into smaller PRs?
|
||||||
- [ ] Have I provided a clear explanation of the changes?
|
- [ ] Have I provided a clear explanation of the changes?
|
||||||
- [ ] Have I considered writing automated tests for the issue?
|
- [ ] Have I considered writing automated tests for the issue?
|
||||||
|
- [ ] If I have text, did I add placeholders for them in locales?
|
||||||
- [ ] Have I tested the changes (manually)?
|
- [ ] Have I tested the changes (manually)?
|
||||||
- [ ] Are all unit tests still passing? (`npm run test`)
|
- [ ] Are all unit tests still passing? (`npm run test`)
|
||||||
- [ ] Are the changes visual?
|
- [ ] Are the changes visual?
|
||||||
|
@ -81,6 +81,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to
|
|||||||
- kyledove
|
- kyledove
|
||||||
- Brumirage
|
- Brumirage
|
||||||
- pkmn_realidea (Paid Commissions)
|
- pkmn_realidea (Paid Commissions)
|
||||||
|
- IceJkai
|
||||||
|
|
||||||
### 🎨 Trainer Portraits
|
### 🎨 Trainer Portraits
|
||||||
- pkmn_realidea (Paid Commissions)
|
- pkmn_realidea (Paid Commissions)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"test:cov": "vitest run --project pre && vitest run --project main --coverage",
|
"test:cov": "vitest run --project pre && vitest run --project main --coverage",
|
||||||
"test:watch": "vitest run --project pre && vitest watch --project main --coverage",
|
"test:watch": "vitest run --project pre && vitest watch --project main --coverage",
|
||||||
"test:silent": "vitest run --project pre && vitest run --project main --silent",
|
"test:silent": "vitest run --project pre && vitest run --project main --silent",
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
"eslint": "eslint --fix .",
|
"eslint": "eslint --fix .",
|
||||||
"eslint-ci": "eslint .",
|
"eslint-ci": "eslint .",
|
||||||
"docs": "typedoc",
|
"docs": "typedoc",
|
||||||
|
BIN
public/audio/bgm/battle_hoenn_champion_g6.mp3
Normal file
BIN
public/fonts/Galmuri11.subset.woff2
Normal file
BIN
public/fonts/Galmuri9.subset.woff2
Normal file
BIN
public/fonts/PokePT_Wansung.woff2
Normal file
BIN
public/fonts/unifont-15.1.05.subset.woff2
Normal file
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 11 KiB |
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "aqua_admin_f.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:efd07ff3ed1e610150a4b8ca18974343:d9b85b9eb11182e9e4669e2bd8b08694:72b7b50231708a9486d5f315824e4df1$"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "aqua_admin.png",
|
"image": "archer.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 80,
|
"w": 80,
|
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 645 B |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "rocket_admin_m.png",
|
"image": "ariana.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 80,
|
"w": 80,
|
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 736 B |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "magma_admin_m.png",
|
"image": "bryony.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 80,
|
"w": 80,
|
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 671 B |
41
public/images/trainer/courtney.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "courtney.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 52,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 52,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 52,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 52,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/trainer/courtney.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "flare_admin_m.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:c30bf82452209a923f4becf13d275a9a:a6355b09f92c9c0388d0b919010f587f:0638dbf213f8a974eb5af76eb1e5ddeb$"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "galactic_admin_f.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "galactic_admin_m.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:3012867f03f02c4ee67a8ab3ad5a000e:77a5f60f1adc158664b3b2ee17bf30fe:7e8259b5177c0a76e5d02d6bdc66affe$"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"textures": [
|
"textures": [
|
||||||
{
|
{
|
||||||
"image": "flare_admin_f.png",
|
"image": "jupiter.png",
|
||||||
"format": "RGBA8888",
|
"format": "RGBA8888",
|
||||||
"size": {
|
"size": {
|
||||||
"w": 80,
|
"w": 80,
|
BIN
public/images/trainer/jupiter.png
Normal file
After Width: | Height: | Size: 657 B |
Before Width: | Height: | Size: 847 B |
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "magma_admin_f.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": true,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:f63ad48affc076f60fae78992c96a2bf:80928b32710abcb28c07c6fc5a425d99:3b961d8852b62aaf24ceb2030c036515$"
|
|
||||||
}
|
|
||||||
}
|
|
41
public/images/trainer/mars.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "mars.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 621 B After Width: | Height: | Size: 621 B |
41
public/images/trainer/matt.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "matt.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
41
public/images/trainer/petrel.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "petrel.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/trainer/petrel.png
Normal file
After Width: | Height: | Size: 728 B |
Before Width: | Height: | Size: 5.0 KiB |
41
public/images/trainer/proton.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "proton.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/trainer/proton.png
Normal file
After Width: | Height: | Size: 670 B |
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"textures": [
|
|
||||||
{
|
|
||||||
"image": "rocket_admin_f.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"scale": 1,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"filename": "0001.png",
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"sourceSize": {
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"spriteSourceSize": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
},
|
|
||||||
"frame": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"w": 80,
|
|
||||||
"h": 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "https://www.codeandweb.com/texturepacker",
|
|
||||||
"version": "3.0",
|
|
||||||
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
|
||||||
}
|
|
||||||
}
|
|
41
public/images/trainer/saturn.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "saturn.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 689 B |
41
public/images/trainer/shelly.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "shelly.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 865 B |
41
public/images/trainer/tabitha.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "tabitha.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 845 B After Width: | Height: | Size: 845 B |
41
public/images/trainer/xerosic.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "xerosic.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "0001.png",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 80,
|
||||||
|
"h": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 789 B After Width: | Height: | Size: 789 B |
440
public/images/types_ja.json
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "types_ja.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 280
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "unknown",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "bug",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 14,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "dark",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 28,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "dragon",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 42,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "electric",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 56,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fairy",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 70,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fighting",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 84,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fire",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 98,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "flying",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 112,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ghost",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 126,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "grass",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 140,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ground",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 154,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ice",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 168,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "normal",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 182,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "poison",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 196,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "psychic",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 210,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "rock",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 224,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "steel",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 238,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "water",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 252,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "stellar",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 266,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/types_ja.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
@ -176,6 +176,27 @@
|
|||||||
"w": 12,
|
"w": 12,
|
||||||
"h": 6
|
"h": 6
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "HP",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 9,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 1,
|
||||||
|
"y": 2,
|
||||||
|
"w": 8,
|
||||||
|
"h": 6
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 112,
|
||||||
|
"y": 0,
|
||||||
|
"w": 8,
|
||||||
|
"h": 6
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 451 B |
@ -281,6 +281,27 @@
|
|||||||
"w": 9,
|
"w": 9,
|
||||||
"h": 8
|
"h": 8
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "empty",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 117,
|
||||||
|
"y": 0,
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 435 B |
@ -176,6 +176,27 @@
|
|||||||
"w": 13,
|
"w": 13,
|
||||||
"h": 7
|
"h": 7
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "HP",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 9,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 1,
|
||||||
|
"w": 9,
|
||||||
|
"h": 7
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 120,
|
||||||
|
"y": 0,
|
||||||
|
"w": 9,
|
||||||
|
"h": 7
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 496 B |
@ -281,6 +281,27 @@
|
|||||||
"w": 9,
|
"w": 9,
|
||||||
"h": 8
|
"h": 8
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "empty",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 117,
|
||||||
|
"y": 0,
|
||||||
|
"w": 1,
|
||||||
|
"h": 8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 430 B After Width: | Height: | Size: 499 B |
3
src/@types/common.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import BattleScene from "#app/battle-scene.js";
|
||||||
|
|
||||||
|
export type ConditionFn = (scene: BattleScene, args?: any[]) => boolean;
|
@ -8,7 +8,7 @@ export interface UserInfo {
|
|||||||
googleId: string;
|
googleId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let loggedInUser: UserInfo = null;
|
export let loggedInUser: UserInfo | null = null;
|
||||||
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
|
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
|
||||||
export const clientSessionId = Utils.randomString(32);
|
export const clientSessionId = Utils.randomString(32);
|
||||||
|
|
||||||
@ -30,11 +30,13 @@ export function updateUserInfo(): Promise<[boolean, integer]> {
|
|||||||
loggedInUser.lastSessionSlot = lastSessionSlot;
|
loggedInUser.lastSessionSlot = lastSessionSlot;
|
||||||
// Migrate old data from before the username was appended
|
// Migrate old data from before the username was appended
|
||||||
[ "data", "sessionData", "sessionData1", "sessionData2", "sessionData3", "sessionData4" ].map(d => {
|
[ "data", "sessionData", "sessionData1", "sessionData2", "sessionData3", "sessionData4" ].map(d => {
|
||||||
if (localStorage.hasOwnProperty(d)) {
|
const lsItem = localStorage.getItem(d);
|
||||||
if (localStorage.hasOwnProperty(`${d}_${loggedInUser.username}`)) {
|
if (lsItem && !!loggedInUser?.username) {
|
||||||
localStorage.setItem(`${d}_${loggedInUser.username}_bak`, localStorage.getItem(`${d}_${loggedInUser.username}`));
|
const lsUserItem = localStorage.getItem(`${d}_${loggedInUser.username}`);
|
||||||
|
if (lsUserItem) {
|
||||||
|
localStorage.setItem(`${d}_${loggedInUser.username}_bak`, lsUserItem);
|
||||||
}
|
}
|
||||||
localStorage.setItem(`${d}_${loggedInUser.username}`, localStorage.getItem(d));
|
localStorage.setItem(`${d}_${loggedInUser.username}`, lsItem);
|
||||||
localStorage.removeItem(d);
|
localStorage.removeItem(d);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -106,8 +106,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
public inputController: InputsController;
|
public inputController: InputsController;
|
||||||
public uiInputs: UiInputs;
|
public uiInputs: UiInputs;
|
||||||
|
|
||||||
public sessionPlayTime: integer = null;
|
public sessionPlayTime: integer | null = null;
|
||||||
public lastSavePlayTime: integer = null;
|
public lastSavePlayTime: integer | null = null;
|
||||||
public masterVolume: number = 0.5;
|
public masterVolume: number = 0.5;
|
||||||
public bgmVolume: number = 1;
|
public bgmVolume: number = 1;
|
||||||
public seVolume: number = 1;
|
public seVolume: number = 1;
|
||||||
@ -122,6 +122,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
|
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
|
||||||
public enableMoveInfo: boolean = true;
|
public enableMoveInfo: boolean = true;
|
||||||
public enableRetries: boolean = false;
|
public enableRetries: boolean = false;
|
||||||
|
public hideIvs: boolean = false;
|
||||||
/**
|
/**
|
||||||
* Determines the condition for a notification should be shown for Candy Upgrades
|
* Determines the condition for a notification should be shown for Candy Upgrades
|
||||||
* - 0 = 'Off'
|
* - 0 = 'Off'
|
||||||
@ -192,8 +193,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
private phaseQueuePrependSpliceIndex: integer;
|
private phaseQueuePrependSpliceIndex: integer;
|
||||||
private nextCommandPhaseQueue: Phase[];
|
private nextCommandPhaseQueue: Phase[];
|
||||||
|
|
||||||
private currentPhase: Phase;
|
private currentPhase: Phase | null;
|
||||||
private standbyPhase: Phase;
|
private standbyPhase: Phase | null;
|
||||||
public field: Phaser.GameObjects.Container;
|
public field: Phaser.GameObjects.Container;
|
||||||
public fieldUI: Phaser.GameObjects.Container;
|
public fieldUI: Phaser.GameObjects.Container;
|
||||||
public charSprite: CharSprite;
|
public charSprite: CharSprite;
|
||||||
@ -213,7 +214,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
public score: integer;
|
public score: integer;
|
||||||
public lockModifierTiers: boolean;
|
public lockModifierTiers: boolean;
|
||||||
public trainer: Phaser.GameObjects.Sprite;
|
public trainer: Phaser.GameObjects.Sprite;
|
||||||
public lastEnemyTrainer: Trainer;
|
public lastEnemyTrainer: Trainer | null;
|
||||||
public currentBattle: Battle;
|
public currentBattle: Battle;
|
||||||
public pokeballCounts: PokeballCounts;
|
public pokeballCounts: PokeballCounts;
|
||||||
public money: integer;
|
public money: integer;
|
||||||
@ -251,7 +252,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
public spritePipeline: SpritePipeline;
|
public spritePipeline: SpritePipeline;
|
||||||
|
|
||||||
private bgm: AnySound;
|
private bgm: AnySound;
|
||||||
private bgmResumeTimer: Phaser.Time.TimerEvent;
|
private bgmResumeTimer: Phaser.Time.TimerEvent | null;
|
||||||
private bgmCache: Set<string> = new Set();
|
private bgmCache: Set<string> = new Set();
|
||||||
private playTimeTimer: Phaser.Time.TimerEvent;
|
private playTimeTimer: Phaser.Time.TimerEvent;
|
||||||
|
|
||||||
@ -700,7 +701,11 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
hasExpSprite(key: string): boolean {
|
hasExpSprite(key: string): boolean {
|
||||||
const keyMatch = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/g.exec(key);
|
const keyMatch = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/g.exec(key);
|
||||||
let k = keyMatch[4];
|
if (!keyMatch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let k = keyMatch[4]!;
|
||||||
if (keyMatch[2]) {
|
if (keyMatch[2]) {
|
||||||
k += "s";
|
k += "s";
|
||||||
}
|
}
|
||||||
@ -723,7 +728,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return this.party;
|
return this.party;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayerPokemon(): PlayerPokemon {
|
getPlayerPokemon(): PlayerPokemon | undefined {
|
||||||
return this.getPlayerField().find(p => p.isActive());
|
return this.getPlayerField().find(p => p.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,7 +745,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return this.currentBattle?.enemyParty || [];
|
return this.currentBattle?.enemyParty || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getEnemyPokemon(): EnemyPokemon {
|
getEnemyPokemon(): EnemyPokemon | undefined {
|
||||||
return this.getEnemyField().find(p => p.isActive());
|
return this.getEnemyField().find(p => p.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -764,6 +769,27 @@ export default class BattleScene extends SceneBase {
|
|||||||
: ret;
|
: ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in doubles battles to redirect moves from one pokemon to another when one faints or is removed from the field
|
||||||
|
* @param removedPokemon {@linkcode Pokemon} the pokemon that is being removed from the field (flee, faint), moves to be redirected FROM
|
||||||
|
* @param allyPokemon {@linkcode Pokemon} the pokemon that will have the moves be redirected TO
|
||||||
|
*/
|
||||||
|
redirectPokemonMoves(removedPokemon: Pokemon, allyPokemon: Pokemon): void {
|
||||||
|
// failsafe: if not a double battle just return
|
||||||
|
if (this.currentBattle.double === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (allyPokemon?.isActive(true)) {
|
||||||
|
let targetingMovePhase: MovePhase;
|
||||||
|
do {
|
||||||
|
targetingMovePhase = this.findPhase(mp => mp instanceof MovePhase && mp.targets.length === 1 && mp.targets[0] === removedPokemon.getBattlerIndex() && mp.pokemon.isPlayer() !== allyPokemon.isPlayer()) as MovePhase;
|
||||||
|
if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) {
|
||||||
|
targetingMovePhase.targets[0] = allyPokemon.getBattlerIndex();
|
||||||
|
}
|
||||||
|
} while (targetingMovePhase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ModifierBar of this scene, which is declared private and therefore not accessible elsewhere
|
* Returns the ModifierBar of this scene, which is declared private and therefore not accessible elsewhere
|
||||||
* @returns {ModifierBar}
|
* @returns {ModifierBar}
|
||||||
@ -782,12 +808,12 @@ export default class BattleScene extends SceneBase {
|
|||||||
return activeOnly ? this.infoToggles.filter(t => t?.isActive()) : this.infoToggles;
|
return activeOnly ? this.infoToggles.filter(t => t?.isActive()) : this.infoToggles;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPokemonById(pokemonId: integer): Pokemon {
|
getPokemonById(pokemonId: integer): Pokemon | null {
|
||||||
const findInParty = (party: Pokemon[]) => party.find(p => p.id === pokemonId);
|
const findInParty = (party: Pokemon[]) => party.find(p => p.id === pokemonId);
|
||||||
return findInParty(this.getParty()) || findInParty(this.getEnemyParty());
|
return (findInParty(this.getParty()) || findInParty(this.getEnemyParty())) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon {
|
addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon {
|
||||||
const pokemon = new PlayerPokemon(this, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
const pokemon = new PlayerPokemon(this, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
||||||
if (postProcess) {
|
if (postProcess) {
|
||||||
postProcess(pokemon);
|
postProcess(pokemon);
|
||||||
@ -957,7 +983,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
p.destroy();
|
p.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentBattle = null;
|
//@ts-ignore - allowing `null` for currentBattle causes a lot of trouble
|
||||||
|
this.currentBattle = null; // TODO: resolve ts-ignore
|
||||||
|
|
||||||
this.biomeWaveText.setText(startingWave.toString());
|
this.biomeWaveText.setText(startingWave.toString());
|
||||||
this.biomeWaveText.setVisible(false);
|
this.biomeWaveText.setVisible(false);
|
||||||
@ -1021,14 +1048,14 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle {
|
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle | null {
|
||||||
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
|
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
|
||||||
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
|
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
|
||||||
let newDouble: boolean;
|
let newDouble: boolean | undefined;
|
||||||
let newBattleType: BattleType;
|
let newBattleType: BattleType;
|
||||||
let newTrainer: Trainer;
|
let newTrainer: Trainer | undefined;
|
||||||
|
|
||||||
let battleConfig: FixedBattleConfig = null;
|
let battleConfig: FixedBattleConfig | null = null;
|
||||||
|
|
||||||
this.resetSeed(newWaveIndex);
|
this.resetSeed(newWaveIndex);
|
||||||
|
|
||||||
@ -1038,7 +1065,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
battleConfig = this.gameMode.getFixedBattle(newWaveIndex);
|
battleConfig = this.gameMode.getFixedBattle(newWaveIndex);
|
||||||
newDouble = battleConfig.double;
|
newDouble = battleConfig.double;
|
||||||
newBattleType = battleConfig.battleType;
|
newBattleType = battleConfig.battleType;
|
||||||
this.executeWithSeedOffset(() => newTrainer = battleConfig.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8);
|
this.executeWithSeedOffset(() => newTrainer = battleConfig?.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8);
|
||||||
if (newTrainer) {
|
if (newTrainer) {
|
||||||
this.field.add(newTrainer);
|
this.field.add(newTrainer);
|
||||||
}
|
}
|
||||||
@ -1078,7 +1105,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
||||||
newDouble = !Utils.randSeedInt(doubleChance.value);
|
newDouble = !Utils.randSeedInt(doubleChance.value);
|
||||||
} else if (newBattleType === BattleType.TRAINER) {
|
} else if (newBattleType === BattleType.TRAINER) {
|
||||||
newDouble = newTrainer.variant === TrainerVariant.DOUBLE;
|
newDouble = newTrainer?.variant === TrainerVariant.DOUBLE;
|
||||||
}
|
}
|
||||||
} else if (!battleConfig) {
|
} else if (!battleConfig) {
|
||||||
newDouble = !!double;
|
newDouble = !!double;
|
||||||
@ -1110,27 +1137,11 @@ export default class BattleScene extends SceneBase {
|
|||||||
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
|
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
|
||||||
|
|
||||||
if (!waveIndex && lastBattle) {
|
if (!waveIndex && lastBattle) {
|
||||||
let isNewBiome = !(lastBattle.waveIndex % 10) || ((this.gameMode.hasShortBiomes || this.gameMode.isDaily) && (lastBattle.waveIndex % 50) === 49);
|
const isWaveIndexMultipleOfTen = !(lastBattle.waveIndex % 10);
|
||||||
if (!isNewBiome && this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 10) < 9) {
|
const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily;
|
||||||
let w = lastBattle.waveIndex - ((lastBattle.waveIndex % 10) - 1);
|
const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0;
|
||||||
let biomeWaves = 1;
|
const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49;
|
||||||
while (w < lastBattle.waveIndex) {
|
const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
|
||||||
let wasNewBiome = false;
|
|
||||||
this.executeWithSeedOffset(() => {
|
|
||||||
wasNewBiome = !Utils.randSeedInt(6 - biomeWaves);
|
|
||||||
}, w << 4);
|
|
||||||
if (wasNewBiome) {
|
|
||||||
biomeWaves = 1;
|
|
||||||
} else {
|
|
||||||
biomeWaves++;
|
|
||||||
}
|
|
||||||
w++;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.executeWithSeedOffset(() => {
|
|
||||||
isNewBiome = !Utils.randSeedInt(6 - biomeWaves);
|
|
||||||
}, lastBattle.waveIndex << 4);
|
|
||||||
}
|
|
||||||
const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
|
const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
|
||||||
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
|
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
|
||||||
this.trySpreadPokerus();
|
this.trySpreadPokerus();
|
||||||
@ -1309,7 +1320,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
let isBoss: boolean;
|
let isBoss: boolean | undefined;
|
||||||
if (forceBoss || (species && (species.subLegendary || species.legendary || species.mythical))) {
|
if (forceBoss || (species && (species.subLegendary || species.legendary || species.mythical))) {
|
||||||
isBoss = true;
|
isBoss = true;
|
||||||
} else {
|
} else {
|
||||||
@ -1608,7 +1619,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
randomSpecies(waveIndex: integer, level: integer, fromArenaPool?: boolean, speciesFilter?: PokemonSpeciesFilter, filterAllEvolutions?: boolean): PokemonSpecies {
|
randomSpecies(waveIndex: integer, level: integer, fromArenaPool?: boolean, speciesFilter?: PokemonSpeciesFilter, filterAllEvolutions?: boolean): PokemonSpecies {
|
||||||
if (fromArenaPool) {
|
if (fromArenaPool) {
|
||||||
return this.arena.randomSpecies(waveIndex, level,null , getPartyLuckValue(this.party));
|
return this.arena.randomSpecies(waveIndex, level, undefined , getPartyLuckValue(this.party));
|
||||||
}
|
}
|
||||||
const filteredSpecies = speciesFilter ? [...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => {
|
const filteredSpecies = speciesFilter ? [...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => {
|
||||||
if (!filterAllEvolutions) {
|
if (!filterAllEvolutions) {
|
||||||
@ -1792,8 +1803,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
return 13.950;
|
return 13.950;
|
||||||
case "battle_johto_champion": //B2W2 Johto Champion Battle
|
case "battle_johto_champion": //B2W2 Johto Champion Battle
|
||||||
return 23.498;
|
return 23.498;
|
||||||
case "battle_hoenn_champion": //B2W2 Hoenn Champion Battle
|
case "battle_hoenn_champion_g5": //B2W2 Hoenn Champion Battle
|
||||||
return 11.328;
|
return 11.328;
|
||||||
|
case "battle_hoenn_champion_g6": //ORAS Hoenn Champion Battle
|
||||||
|
return 11.762;
|
||||||
case "battle_sinnoh_champion": //B2W2 Sinnoh Champion Battle
|
case "battle_sinnoh_champion": //B2W2 Sinnoh Champion Battle
|
||||||
return 12.235;
|
return 12.235;
|
||||||
case "battle_champion_alder": //BW Unova Champion Battle
|
case "battle_champion_alder": //BW Unova Champion Battle
|
||||||
@ -1964,11 +1977,11 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Phase Functions */
|
/* Phase Functions */
|
||||||
getCurrentPhase(): Phase {
|
getCurrentPhase(): Phase | null {
|
||||||
return this.currentPhase;
|
return this.currentPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStandbyPhase(): Phase {
|
getStandbyPhase(): Phase | null {
|
||||||
return this.standbyPhase;
|
return this.standbyPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2046,7 +2059,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
if (this.phaseQueuePrepend.length) {
|
if (this.phaseQueuePrepend.length) {
|
||||||
while (this.phaseQueuePrepend.length) {
|
while (this.phaseQueuePrepend.length) {
|
||||||
this.phaseQueue.unshift(this.phaseQueuePrepend.pop());
|
const poppedPhase = this.phaseQueuePrepend.pop();
|
||||||
|
if (poppedPhase) {
|
||||||
|
this.phaseQueue.unshift(poppedPhase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this.phaseQueue.length) {
|
if (!this.phaseQueue.length) {
|
||||||
@ -2054,23 +2070,26 @@ export default class BattleScene extends SceneBase {
|
|||||||
// Clear the conditionalQueue if there are no phases left in the phaseQueue
|
// Clear the conditionalQueue if there are no phases left in the phaseQueue
|
||||||
this.conditionalQueue = [];
|
this.conditionalQueue = [];
|
||||||
}
|
}
|
||||||
this.currentPhase = this.phaseQueue.shift();
|
|
||||||
|
this.currentPhase = this.phaseQueue.shift() ?? null;
|
||||||
|
|
||||||
// Check if there are any conditional phases queued
|
// Check if there are any conditional phases queued
|
||||||
if (this.conditionalQueue?.length) {
|
if (this.conditionalQueue?.length) {
|
||||||
// Retrieve the first conditional phase from the queue
|
// Retrieve the first conditional phase from the queue
|
||||||
const conditionalPhase = this.conditionalQueue.shift();
|
const conditionalPhase = this.conditionalQueue.shift();
|
||||||
// Evaluate the condition associated with the phase
|
// Evaluate the condition associated with the phase
|
||||||
if (conditionalPhase[0]()) {
|
if (conditionalPhase?.[0]()) {
|
||||||
// If the condition is met, add the phase to the phase queue
|
// If the condition is met, add the phase to the phase queue
|
||||||
this.pushPhase(conditionalPhase[1]);
|
this.pushPhase(conditionalPhase[1]);
|
||||||
} else {
|
} else if (conditionalPhase) {
|
||||||
// If the condition is not met, re-add the phase back to the front of the conditional queue
|
// If the condition is not met, re-add the phase back to the front of the conditional queue
|
||||||
this.conditionalQueue.unshift(conditionalPhase);
|
this.conditionalQueue.unshift(conditionalPhase);
|
||||||
|
} else {
|
||||||
|
console.warn("condition phase is undefined/null!", conditionalPhase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentPhase.start();
|
this.currentPhase?.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
overridePhase(phase: Phase): boolean {
|
overridePhase(phase: Phase): boolean {
|
||||||
@ -2085,7 +2104,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
findPhase(phaseFilter: (phase: Phase) => boolean): Phase {
|
findPhase(phaseFilter: (phase: Phase) => boolean): Phase | undefined {
|
||||||
return this.phaseQueue.find(phaseFilter);
|
return this.phaseQueue.find(phaseFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2144,7 +2163,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
* @param promptDelay optional param for MessagePhase constructor
|
* @param promptDelay optional param for MessagePhase constructor
|
||||||
* @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue
|
* @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue
|
||||||
*/
|
*/
|
||||||
queueMessage(message: string, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer, defer?: boolean) {
|
queueMessage(message: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null, defer?: boolean | null) {
|
||||||
const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay);
|
const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay);
|
||||||
if (!defer) {
|
if (!defer) {
|
||||||
// adds to the end of PhaseQueuePrepend
|
// adds to the end of PhaseQueuePrepend
|
||||||
@ -2180,7 +2199,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
return Math.floor(moneyValue / 10) * 10;
|
return Math.floor(moneyValue / 10) * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<boolean> {
|
addModifier(modifier: Modifier | null, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<boolean> {
|
||||||
|
if (!modifier) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let success = false;
|
let success = false;
|
||||||
const soundName = modifier.type.soundName;
|
const soundName = modifier.type.soundName;
|
||||||
@ -2200,7 +2222,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
} else if (!virtual) {
|
} else if (!virtual) {
|
||||||
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
|
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
|
||||||
this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, null, true);
|
this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, undefined, true);
|
||||||
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(success => resolve(success));
|
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(success => resolve(success));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2300,7 +2322,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null;
|
const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null;
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
Utils.executeIf(source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source, cancelled)).then(() => {
|
Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => {
|
||||||
if (cancelled.value) {
|
if (cancelled.value) {
|
||||||
return resolve(false);
|
return resolve(false);
|
||||||
}
|
}
|
||||||
@ -2381,7 +2403,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
party.forEach((enemyPokemon: EnemyPokemon, i: integer) => {
|
party.forEach((enemyPokemon: EnemyPokemon, i: integer) => {
|
||||||
const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss);
|
const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer?.config.isBoss);
|
||||||
let upgradeChance = 32;
|
let upgradeChance = 32;
|
||||||
if (isBoss) {
|
if (isBoss) {
|
||||||
upgradeChance /= 2;
|
upgradeChance /= 2;
|
||||||
@ -2389,9 +2411,9 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (isFinalBoss) {
|
if (isFinalBoss) {
|
||||||
upgradeChance /= 8;
|
upgradeChance /= 8;
|
||||||
}
|
}
|
||||||
const modifierChance = this.gameMode.getEnemyModifierChance(isBoss);
|
const modifierChance = this.gameMode.getEnemyModifierChance(isBoss!); // TODO: is this bang correct?
|
||||||
let pokemonModifierChance = modifierChance;
|
let pokemonModifierChance = modifierChance;
|
||||||
if (this.currentBattle.battleType === BattleType.TRAINER)
|
if (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer)
|
||||||
pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line
|
pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (let c = 0; c < chances; c++) {
|
for (let c = 0; c < chances; c++) {
|
||||||
@ -2510,7 +2532,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return (player ? this.modifiers : this.enemyModifiers).filter(m => (modifierFilter as ModifierPredicate)(m));
|
return (player ? this.modifiers : this.enemyModifiers).filter(m => (modifierFilter as ModifierPredicate)(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier {
|
findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier | undefined {
|
||||||
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m));
|
return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2546,7 +2568,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
return appliedModifiers;
|
return appliedModifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyModifier(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier {
|
applyModifier(modifierType: Constructor<Modifier>, player: boolean = true, ...args: any[]): PersistentModifier | null {
|
||||||
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args));
|
||||||
for (const modifier of modifiers) {
|
for (const modifier of modifiers) {
|
||||||
if (modifier.apply(args)) {
|
if (modifier.apply(args)) {
|
||||||
@ -2633,7 +2655,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
initFinalBossPhaseTwo(pokemon: Pokemon): void {
|
initFinalBossPhaseTwo(pokemon: Pokemon): void {
|
||||||
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
|
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
|
||||||
this.fadeOutBgm(Utils.fixedInt(2000), false);
|
this.fadeOutBgm(Utils.fixedInt(2000), false);
|
||||||
this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, null, () => {
|
this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, undefined, () => {
|
||||||
this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true);
|
this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true);
|
||||||
pokemon.generateAndPopulateMoveset(1);
|
pokemon.generateAndPopulateMoveset(1);
|
||||||
this.setFieldScale(0.75);
|
this.setFieldScale(0.75);
|
||||||
|
@ -39,7 +39,7 @@ export interface TurnCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TurnCommands {
|
interface TurnCommands {
|
||||||
[key: integer]: TurnCommand
|
[key: integer]: TurnCommand | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Battle {
|
export default class Battle {
|
||||||
@ -47,8 +47,8 @@ export default class Battle {
|
|||||||
public waveIndex: integer;
|
public waveIndex: integer;
|
||||||
public battleType: BattleType;
|
public battleType: BattleType;
|
||||||
public battleSpec: BattleSpec;
|
public battleSpec: BattleSpec;
|
||||||
public trainer: Trainer;
|
public trainer: Trainer | null;
|
||||||
public enemyLevels: integer[];
|
public enemyLevels: integer[] | undefined;
|
||||||
public enemyParty: EnemyPokemon[];
|
public enemyParty: EnemyPokemon[];
|
||||||
public seenEnemyPartyMemberIds: Set<integer>;
|
public seenEnemyPartyMemberIds: Set<integer>;
|
||||||
public double: boolean;
|
public double: boolean;
|
||||||
@ -62,26 +62,26 @@ export default class Battle {
|
|||||||
public escapeAttempts: integer;
|
public escapeAttempts: integer;
|
||||||
public lastMove: Moves;
|
public lastMove: Moves;
|
||||||
public battleSeed: string;
|
public battleSeed: string;
|
||||||
private battleSeedState: string;
|
private battleSeedState: string | null;
|
||||||
public moneyScattered: number;
|
public moneyScattered: number;
|
||||||
public lastUsedPokeball: PokeballType;
|
public lastUsedPokeball: PokeballType | null;
|
||||||
public playerFaints: number; // The amount of times pokemon on the players side have fainted
|
public playerFaints: number; // The amount of times pokemon on the players side have fainted
|
||||||
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
|
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
|
||||||
|
|
||||||
private rngCounter: integer = 0;
|
private rngCounter: integer = 0;
|
||||||
|
|
||||||
constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) {
|
constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer?: Trainer, double?: boolean) {
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
this.waveIndex = waveIndex;
|
this.waveIndex = waveIndex;
|
||||||
this.battleType = battleType;
|
this.battleType = battleType;
|
||||||
this.trainer = trainer;
|
this.trainer = trainer!; //TODO: is this bang correct?
|
||||||
this.initBattleSpec();
|
this.initBattleSpec();
|
||||||
this.enemyLevels = battleType !== BattleType.TRAINER
|
this.enemyLevels = battleType !== BattleType.TRAINER
|
||||||
? new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave())
|
? new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave())
|
||||||
: trainer.getPartyLevels(this.waveIndex);
|
: trainer?.getPartyLevels(this.waveIndex);
|
||||||
this.enemyParty = [];
|
this.enemyParty = [];
|
||||||
this.seenEnemyPartyMemberIds = new Set<integer>();
|
this.seenEnemyPartyMemberIds = new Set<integer>();
|
||||||
this.double = double;
|
this.double = double!; //TODO: is this bang correct?
|
||||||
this.enemySwitchCounter = 0;
|
this.enemySwitchCounter = 0;
|
||||||
this.turn = 0;
|
this.turn = 0;
|
||||||
this.playerParticipantIds = new Set<integer>();
|
this.playerParticipantIds = new Set<integer>();
|
||||||
@ -159,6 +159,7 @@ export default class Battle {
|
|||||||
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
|
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
|
||||||
this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferrable, false).map(i => {
|
this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferrable, false).map(i => {
|
||||||
const ret = i as PokemonHeldItemModifier;
|
const ret = i as PokemonHeldItemModifier;
|
||||||
|
//@ts-ignore - this is awful to fix/change
|
||||||
ret.pokemonId = null;
|
ret.pokemonId = null;
|
||||||
return ret;
|
return ret;
|
||||||
}));
|
}));
|
||||||
@ -177,7 +178,7 @@ export default class Battle {
|
|||||||
const userLocale = navigator.language || "en-US";
|
const userLocale = navigator.language || "en-US";
|
||||||
const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale);
|
const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale);
|
||||||
const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount });
|
const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount });
|
||||||
scene.queueMessage(message, null, true);
|
scene.queueMessage(message, undefined, true);
|
||||||
|
|
||||||
scene.currentBattle.moneyScattered = 0;
|
scene.currentBattle.moneyScattered = 0;
|
||||||
}
|
}
|
||||||
@ -200,16 +201,16 @@ export default class Battle {
|
|||||||
scene.updateScoreText();
|
scene.updateScoreText();
|
||||||
}
|
}
|
||||||
|
|
||||||
getBgmOverride(scene: BattleScene): string {
|
getBgmOverride(scene: BattleScene): string | null {
|
||||||
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
||||||
if (this.battleType === BattleType.TRAINER) {
|
if (this.battleType === BattleType.TRAINER) {
|
||||||
if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length) {
|
if (!this.started && this.trainer?.config.encounterBgm && this.trainer?.getEncounterMessages()?.length) {
|
||||||
return `encounter_${this.trainer.getEncounterBgm()}`;
|
return `encounter_${this.trainer?.getEncounterBgm()}`;
|
||||||
}
|
}
|
||||||
if (scene.musicPreference === 0) {
|
if (scene.musicPreference === 0) {
|
||||||
return this.trainer.getBattleBgm();
|
return this.trainer?.getBattleBgm()!; // TODO: is this bang correct?
|
||||||
} else {
|
} else {
|
||||||
return this.trainer.getMixedBattleBgm();
|
return this.trainer?.getMixedBattleBgm()!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
} else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) {
|
} else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) {
|
||||||
return "end_summit";
|
return "end_summit";
|
||||||
@ -382,7 +383,7 @@ export default class Battle {
|
|||||||
|
|
||||||
export class FixedBattle extends Battle {
|
export class FixedBattle extends Battle {
|
||||||
constructor(scene: BattleScene, waveIndex: integer, config: FixedBattleConfig) {
|
constructor(scene: BattleScene, waveIndex: integer, config: FixedBattleConfig) {
|
||||||
super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : null, config.double);
|
super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : undefined, config.double);
|
||||||
if (config.getEnemyParty) {
|
if (config.getEnemyParty) {
|
||||||
this.enemyParty = config.getEnemyParty(scene);
|
this.enemyParty = config.getEnemyParty(scene);
|
||||||
}
|
}
|
||||||
@ -425,22 +426,28 @@ export class FixedBattleConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to generate a random trainer for evil team trainers and the elite 4/champion
|
* Helper function to generate a random trainer for evil team trainers and the elite 4/champion
|
||||||
* @param trainerPool The TrainerType or list of TrainerTypes that can possibly be generated
|
* @param trainerPool The TrainerType or list of TrainerTypes that can possibly be generated
|
||||||
* @param randomGender whether or not to randomly (50%) generate a female trainer (for use with evil team grunts)
|
* @param randomGender whether or not to randomly (50%) generate a female trainer (for use with evil team grunts)
|
||||||
|
* @param seedOffset the seed offset to use for the random generation of the trainer
|
||||||
* @returns the generated trainer
|
* @returns the generated trainer
|
||||||
*/
|
*/
|
||||||
function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false): GetTrainerFunc {
|
function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc {
|
||||||
return (scene: BattleScene) => {
|
return (scene: BattleScene) => {
|
||||||
const rand = Utils.randSeedInt(trainerPool.length);
|
const rand = Utils.randSeedInt(trainerPool.length);
|
||||||
const trainerTypes: TrainerType[] = [];
|
const trainerTypes: TrainerType[] = [];
|
||||||
for (const trainerPoolEntry of trainerPool) {
|
|
||||||
const trainerType = Array.isArray(trainerPoolEntry)
|
scene.executeWithSeedOffset(() => {
|
||||||
? Utils.randSeedItem(trainerPoolEntry)
|
for (const trainerPoolEntry of trainerPool) {
|
||||||
: trainerPoolEntry;
|
const trainerType = Array.isArray(trainerPoolEntry)
|
||||||
trainerTypes.push(trainerType);
|
? Utils.randSeedItem(trainerPoolEntry)
|
||||||
}
|
: trainerPoolEntry;
|
||||||
|
trainerTypes.push(trainerType);
|
||||||
|
}
|
||||||
|
}, seedOffset);
|
||||||
|
|
||||||
let trainerGender = TrainerVariant.DEFAULT;
|
let trainerGender = TrainerVariant.DEFAULT;
|
||||||
if (randomGender) {
|
if (randomGender) {
|
||||||
trainerGender = (Utils.randInt(2) === 0) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
|
trainerGender = (Utils.randInt(2) === 0) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT;
|
||||||
@ -486,13 +493,13 @@ export const classicFixedBattles: FixedBattleConfigs = {
|
|||||||
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)),
|
||||||
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_ADMIN, TrainerType.MAGMA_ADMIN, TrainerType.AQUA_ADMIN, TrainerType.GALACTIC_ADMIN, TrainerType.PLASMA_SAGE, TrainerType.FLARE_ADMIN ], true)),
|
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ] ], true)),
|
||||||
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
.setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)),
|
||||||
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)),
|
||||||
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_ADMIN, TrainerType.MAGMA_ADMIN, TrainerType.AQUA_ADMIN, TrainerType.GALACTIC_ADMIN, TrainerType.PLASMA_SAGE, TrainerType.FLARE_ADMIN ], true)),
|
.setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ] ], true,1)),
|
||||||
[115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
[115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35)
|
||||||
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])),
|
.setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])),
|
||||||
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
[145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER)
|
||||||
|
@ -20,7 +20,7 @@ export function getKeyWithKeycode(config, keycode) {
|
|||||||
*/
|
*/
|
||||||
export function getSettingNameWithKeycode(config, keycode) {
|
export function getSettingNameWithKeycode(config, keycode) {
|
||||||
const key = getKeyWithKeycode(config, keycode);
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
return config.custom[key];
|
return key ? config.custom[key] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +32,7 @@ export function getSettingNameWithKeycode(config, keycode) {
|
|||||||
*/
|
*/
|
||||||
export function getIconWithKeycode(config, keycode) {
|
export function getIconWithKeycode(config, keycode) {
|
||||||
const key = getKeyWithKeycode(config, keycode);
|
const key = getKeyWithKeycode(config, keycode);
|
||||||
return config.icons[key];
|
return key ? config.icons[key] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,15 +122,21 @@ export function assign(config, settingNameTarget, keycode): boolean {
|
|||||||
// if it was already bound, we delete the bind
|
// if it was already bound, we delete the bind
|
||||||
if (previousSettingName) {
|
if (previousSettingName) {
|
||||||
const previousKey = getKeyWithSettingName(config, previousSettingName);
|
const previousKey = getKeyWithSettingName(config, previousSettingName);
|
||||||
config.custom[previousKey] = -1;
|
if (previousKey) {
|
||||||
|
config.custom[previousKey] = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// then, we need to delete the current key for this settingName
|
// then, we need to delete the current key for this settingName
|
||||||
const currentKey = getKeyWithSettingName(config, settingNameTarget);
|
const currentKey = getKeyWithSettingName(config, settingNameTarget);
|
||||||
config.custom[currentKey] = -1;
|
if (currentKey) {
|
||||||
|
config.custom[currentKey] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// then, the new key is assigned to the new settingName
|
// then, the new key is assigned to the new settingName
|
||||||
const newKey = getKeyWithKeycode(config, keycode);
|
const newKey = getKeyWithKeycode(config, keycode);
|
||||||
config.custom[newKey] = settingNameTarget;
|
if (newKey) {
|
||||||
|
config.custom[newKey] = settingNameTarget;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +151,12 @@ export function swap(config, settingNameTarget, keycode) {
|
|||||||
const new_key = getKeyWithKeycode(config, keycode);
|
const new_key = getKeyWithKeycode(config, keycode);
|
||||||
const new_settingName = getSettingNameWithKey(config, new_key);
|
const new_settingName = getSettingNameWithKey(config, new_key);
|
||||||
|
|
||||||
config.custom[prev_key] = new_settingName;
|
if (prev_key) {
|
||||||
config.custom[new_key] = prev_settingName;
|
config.custom[prev_key] = new_settingName;
|
||||||
|
}
|
||||||
|
if (new_key) {
|
||||||
|
config.custom[new_key] = prev_settingName;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +171,9 @@ export function deleteBind(config, settingName) {
|
|||||||
if (config.blacklist.includes(key)) {
|
if (config.blacklist.includes(key)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
config.custom[key] = -1;
|
if (key) {
|
||||||
|
config.custom[key] = -1;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { BattleStat, getBattleStatName } from "./battle-stat";
|
|||||||
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||||
import { getPokemonNameWithAffix } from "../messages";
|
import { getPokemonNameWithAffix } from "../messages";
|
||||||
import { Weather, WeatherType } from "./weather";
|
import { Weather, WeatherType } from "./weather";
|
||||||
import { BattlerTag, GroundedTag } from "./battler-tags";
|
import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags";
|
||||||
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||||
import { Gender } from "./gender";
|
import { Gender } from "./gender";
|
||||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit } from "./move";
|
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit } from "./move";
|
||||||
@ -120,7 +120,7 @@ export class Ability implements Localizable {
|
|||||||
type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>;
|
type AbAttrApplyFunc<TAttr extends AbAttr> = (attr: TAttr, passive: boolean) => boolean | Promise<boolean>;
|
||||||
type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
type AbAttrCondition = (pokemon: Pokemon) => boolean;
|
||||||
|
|
||||||
type PokemonAttackCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean;
|
||||||
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean;
|
||||||
type PokemonStatChangeCondition = (target: Pokemon, statsChanged: BattleStat[], levels: integer) => boolean;
|
type PokemonStatChangeCondition = (target: Pokemon, statsChanged: BattleStat[], levels: integer) => boolean;
|
||||||
|
|
||||||
@ -132,11 +132,11 @@ export abstract class AbAttr {
|
|||||||
this.showAbility = showAbility;
|
this.showAbility = showAbility;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const statChangePhase of statChangePhases) {
|
for (const statChangePhase of statChangePhases) {
|
||||||
if (!this.selfTarget && !statChangePhase.getPokemon().summonData) {
|
if (!this.selfTarget && !statChangePhase.getPokemon()?.summonData) {
|
||||||
pokemon.scene.pushPhase(statChangePhase);
|
pokemon.scene.pushPhase(statChangePhase);
|
||||||
} else { // TODO: This causes the ability bar to be shown at the wrong time
|
} else { // TODO: This causes the ability bar to be shown at the wrong time
|
||||||
pokemon.scene.unshiftPhase(statChangePhase);
|
pokemon.scene.unshiftPhase(statChangePhase);
|
||||||
@ -240,7 +240,7 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr {
|
|||||||
type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move) => boolean;
|
type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move) => boolean;
|
||||||
|
|
||||||
export class PreDefendAbAttr extends AbAttr {
|
export class PreDefendAbAttr extends AbAttr {
|
||||||
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,14 +352,14 @@ export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplier
|
|||||||
* @see {@linkcode getCondition}
|
* @see {@linkcode getCondition}
|
||||||
*/
|
*/
|
||||||
export class TypeImmunityAbAttr extends PreDefendAbAttr {
|
export class TypeImmunityAbAttr extends PreDefendAbAttr {
|
||||||
private immuneType: Type;
|
private immuneType: Type | null;
|
||||||
private condition: AbAttrCondition;
|
private condition: AbAttrCondition | null;
|
||||||
|
|
||||||
constructor(immuneType: Type, condition?: AbAttrCondition) {
|
constructor(immuneType: Type | null, condition?: AbAttrCondition) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.immuneType = immuneType;
|
this.immuneType = immuneType;
|
||||||
this.condition = condition;
|
this.condition = condition!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,7 +386,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCondition(): AbAttrCondition {
|
override getCondition(): AbAttrCondition | null {
|
||||||
return this.condition;
|
return this.condition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,11 +491,54 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostDefendAbAttr extends AbAttr {
|
export class PostDefendAbAttr extends AbAttr {
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the effects of Gulp Missile when the user is hit by an attack.
|
||||||
|
* @extends PostDefendAbAttr
|
||||||
|
*/
|
||||||
|
export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Damages the attacker and triggers the secondary effect based on the form or the BattlerTagType.
|
||||||
|
* @param {Pokemon} pokemon - The defending Pokemon.
|
||||||
|
* @param passive - n/a
|
||||||
|
* @param {Pokemon} attacker - The attacking Pokemon.
|
||||||
|
* @param {Move} move - The move being used.
|
||||||
|
* @param {HitResult} hitResult - n/a
|
||||||
|
* @param {any[]} args - n/a
|
||||||
|
* @returns Whether the effects of the ability are applied.
|
||||||
|
*/
|
||||||
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
||||||
|
const battlerTag = pokemon.getTag(GulpMissileTag);
|
||||||
|
if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
|
||||||
|
|
||||||
|
if (!cancelled.value) {
|
||||||
|
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battlerTag.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, attacker.getBattlerIndex(), false, [ BattleStat.DEF ], -1));
|
||||||
|
} else {
|
||||||
|
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
pokemon.removeTag(battlerTag.tagType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {
|
export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {
|
||||||
|
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
@ -838,7 +881,7 @@ export class EffectSporeAbAttr extends PostDefendContactApplyStatusEffectAbAttr
|
|||||||
export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
|
export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
|
||||||
private chance: integer;
|
private chance: integer;
|
||||||
private tagType: BattlerTagType;
|
private tagType: BattlerTagType;
|
||||||
private turnCount: integer;
|
private turnCount: integer | undefined;
|
||||||
|
|
||||||
constructor(chance: integer, tagType: BattlerTagType, turnCount?: integer) {
|
constructor(chance: integer, tagType: BattlerTagType, turnCount?: integer) {
|
||||||
super();
|
super();
|
||||||
@ -875,7 +918,7 @@ export class PostDefendCritStatChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCondition(): AbAttrCondition {
|
getCondition(): AbAttrCondition {
|
||||||
return (pokemon: Pokemon) => pokemon.turnData.attacksReceived.length && pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1].critical;
|
return (pokemon: Pokemon) => pokemon.turnData.attacksReceived.length !== 0 && pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1].critical;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,14 +984,19 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
|
export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
|
||||||
private weatherType: WeatherType;
|
private weatherType: WeatherType;
|
||||||
|
protected condition: PokemonDefendCondition | null;
|
||||||
|
|
||||||
constructor(weatherType: WeatherType) {
|
constructor(weatherType: WeatherType, condition?: PokemonDefendCondition) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.weatherType = weatherType;
|
this.weatherType = weatherType;
|
||||||
|
this.condition = condition ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
|
if (this.condition !== null && !this.condition(pokemon, attacker, move)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!pokemon.scene.arena.weather?.isImmutable()) {
|
if (!pokemon.scene.arena.weather?.isImmutable()) {
|
||||||
return pokemon.scene.arena.trySetWeather(this.weatherType, true);
|
return pokemon.scene.arena.trySetWeather(this.weatherType, true);
|
||||||
}
|
}
|
||||||
@ -1052,7 +1100,7 @@ export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PreAttackAbAttr extends AbAttr {
|
export class PreAttackAbAttr extends AbAttr {
|
||||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1065,7 +1113,7 @@ export class PreAttackAbAttr extends AbAttr {
|
|||||||
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
|
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
|
||||||
private chanceMultiplier: number;
|
private chanceMultiplier: number;
|
||||||
|
|
||||||
constructor(chanceMultiplier?: number) {
|
constructor(chanceMultiplier: number) {
|
||||||
super(true);
|
super(true);
|
||||||
this.chanceMultiplier = chanceMultiplier;
|
this.chanceMultiplier = chanceMultiplier;
|
||||||
}
|
}
|
||||||
@ -1446,7 +1494,7 @@ export class FieldMovePowerBoostAbAttr extends AbAttr {
|
|||||||
this.powerMultiplier = powerMultiplier;
|
this.powerMultiplier = powerMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
|
applyPreAttack(pokemon: Pokemon | null, passive: boolean | null, defender: Pokemon | null, move: Move, args: any[]): boolean {
|
||||||
if (this.condition(pokemon, defender, move)) {
|
if (this.condition(pokemon, defender, move)) {
|
||||||
(args[0] as Utils.NumberHolder).value *= this.powerMultiplier;
|
(args[0] as Utils.NumberHolder).value *= this.powerMultiplier;
|
||||||
|
|
||||||
@ -1500,14 +1548,14 @@ export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr
|
|||||||
export class BattleStatMultiplierAbAttr extends AbAttr {
|
export class BattleStatMultiplierAbAttr extends AbAttr {
|
||||||
private battleStat: BattleStat;
|
private battleStat: BattleStat;
|
||||||
private multiplier: number;
|
private multiplier: number;
|
||||||
private condition: PokemonAttackCondition;
|
private condition: PokemonAttackCondition | null;
|
||||||
|
|
||||||
constructor(battleStat: BattleStat, multiplier: number, condition?: PokemonAttackCondition) {
|
constructor(battleStat: BattleStat, multiplier: number, condition?: PokemonAttackCondition) {
|
||||||
super(false);
|
super(false);
|
||||||
|
|
||||||
this.battleStat = battleStat;
|
this.battleStat = battleStat;
|
||||||
this.multiplier = multiplier;
|
this.multiplier = multiplier;
|
||||||
this.condition = condition;
|
this.condition = condition!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
applyBattleStat(pokemon: Pokemon, passive: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise<boolean> {
|
applyBattleStat(pokemon: Pokemon, passive: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise<boolean> {
|
||||||
@ -1536,7 +1584,7 @@ export class PostAttackAbAttr extends AbAttr {
|
|||||||
* applying the effect of any inherited class. This can be changed by providing a different {@link attackCondition} to the constructor. See {@link ConfusionOnStatusEffectAbAttr}
|
* applying the effect of any inherited class. This can be changed by providing a different {@link attackCondition} to the constructor. See {@link ConfusionOnStatusEffectAbAttr}
|
||||||
* for an example of an effect that does not require a damaging move.
|
* for an example of an effect that does not require a damaging move.
|
||||||
*/
|
*/
|
||||||
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise<boolean> {
|
||||||
// When attackRequired is true, we require the move to be an attack move and to deal damage before checking secondary requirements.
|
// When attackRequired is true, we require the move to be an attack move and to deal damage before checking secondary requirements.
|
||||||
// If attackRequired is false, we always defer to the secondary requirements.
|
// If attackRequired is false, we always defer to the secondary requirements.
|
||||||
if (this.attackCondition(pokemon, defender, move)) {
|
if (this.attackCondition(pokemon, defender, move)) {
|
||||||
@ -1549,18 +1597,18 @@ export class PostAttackAbAttr extends AbAttr {
|
|||||||
/**
|
/**
|
||||||
* This method is only called after {@link applyPostAttack} has already been applied. Use this for handling checks specific to the ability in question.
|
* This method is only called after {@link applyPostAttack} has already been applied. Use this for handling checks specific to the ability in question.
|
||||||
*/
|
*/
|
||||||
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise<boolean> {
|
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
||||||
private stealCondition: PokemonAttackCondition;
|
private stealCondition: PokemonAttackCondition | null;
|
||||||
|
|
||||||
constructor(stealCondition?: PokemonAttackCondition) {
|
constructor(stealCondition?: PokemonAttackCondition) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.stealCondition = stealCondition;
|
this.stealCondition = stealCondition!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
|
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
|
||||||
@ -1644,12 +1692,12 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
||||||
private condition: PokemonDefendCondition;
|
private condition: PokemonDefendCondition | null;
|
||||||
|
|
||||||
constructor(condition?: PokemonDefendCondition) {
|
constructor(condition?: PokemonDefendCondition) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.condition = condition;
|
this.condition = condition!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise<boolean> {
|
||||||
@ -2140,17 +2188,17 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
target.getAbility().hasAttr(UncopiableAbilityAbAttr) &&
|
target!.getAbility().hasAttr(UncopiableAbilityAbAttr) &&
|
||||||
// Wonder Guard is normally uncopiable so has the attribute, but Trace specifically can copy it
|
// Wonder Guard is normally uncopiable so has the attribute, but Trace specifically can copy it
|
||||||
!(pokemon.hasAbility(Abilities.TRACE) && target.getAbility().id === Abilities.WONDER_GUARD)
|
!(pokemon.hasAbility(Abilities.TRACE) && target!.getAbility().id === Abilities.WONDER_GUARD)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.target = target;
|
this.target = target!;
|
||||||
this.targetAbilityName = allAbilities[target.getAbility().id].name;
|
this.targetAbilityName = allAbilities[target!.getAbility().id].name;
|
||||||
pokemon.summonData.ability = target.getAbility().id;
|
pokemon.summonData.ability = target!.getAbility().id;
|
||||||
setAbilityRevealed(target);
|
setAbilityRevealed(target!);
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2197,7 +2245,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const pokemon of allowedParty) {
|
for (const pokemon of allowedParty) {
|
||||||
if (this.statusEffect.includes(pokemon.status?.effect)) {
|
if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) {
|
||||||
pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
||||||
pokemon.resetStatus(false);
|
pokemon.resetStatus(false);
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
@ -2253,6 +2301,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
target = targets[0];
|
target = targets[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target = target!; // compiler doesn't know its guranteed to be defined
|
||||||
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
||||||
pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
|
||||||
pokemon.summonData.ability = target.getAbility().id;
|
pokemon.summonData.ability = target.getAbility().id;
|
||||||
@ -2260,7 +2309,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
pokemon.summonData.fusionGender = target.getFusionGender();
|
pokemon.summonData.fusionGender = target.getFusionGender();
|
||||||
pokemon.summonData.stats = [ pokemon.stats[Stat.HP] ].concat(target.stats.slice(1));
|
pokemon.summonData.stats = [ pokemon.stats[Stat.HP] ].concat(target.stats.slice(1));
|
||||||
pokemon.summonData.battleStats = target.summonData.battleStats.slice(0);
|
pokemon.summonData.battleStats = target.summonData.battleStats.slice(0);
|
||||||
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m.moveId, m.ppUsed, m.ppUp));
|
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m!.moveId, m!.ppUsed, m!.ppUp)); // TODO: are those bangs correct?
|
||||||
pokemon.summonData.types = target.getTypes();
|
pokemon.summonData.types = target.getTypes();
|
||||||
|
|
||||||
pokemon.scene.playSound("PRSFX- Transform");
|
pokemon.scene.playSound("PRSFX- Transform");
|
||||||
@ -2307,7 +2356,7 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr {
|
|||||||
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
||||||
*/
|
*/
|
||||||
applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
const weatherType = pokemon.scene.arena.weather.weatherType;
|
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
||||||
let turnOffWeather = false;
|
let turnOffWeather = false;
|
||||||
|
|
||||||
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
|
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
|
||||||
@ -2388,18 +2437,18 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PreStatChangeAbAttr extends AbAttr {
|
export class PreStatChangeAbAttr extends AbAttr {
|
||||||
applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
applyPreStatChange(pokemon: Pokemon | null, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProtectStatAbAttr extends PreStatChangeAbAttr {
|
export class ProtectStatAbAttr extends PreStatChangeAbAttr {
|
||||||
private protectedStat: BattleStat;
|
private protectedStat: BattleStat | null;
|
||||||
|
|
||||||
constructor(protectedStat?: BattleStat) {
|
constructor(protectedStat?: BattleStat) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.protectedStat = protectedStat;
|
this.protectedStat = protectedStat!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
@ -2415,7 +2464,7 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr {
|
|||||||
return i18next.t("abilityTriggers:protectStat", {
|
return i18next.t("abilityTriggers:protectStat", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName,
|
abilityName,
|
||||||
statName: this.protectedStat !== undefined ? getBattleStatName(this.protectedStat) : i18next.t("battle:stats")
|
statName: this.protectedStat ? getBattleStatName(this.protectedStat) : i18next.t("battle:stats")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2455,7 +2504,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PreSetStatusAbAttr extends AbAttr {
|
export class PreSetStatusAbAttr extends AbAttr {
|
||||||
applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2666,7 +2715,7 @@ export class BlockStatusDamageAbAttr extends AbAttr {
|
|||||||
* @returns Returns true if status damage is blocked
|
* @returns Returns true if status damage is blocked
|
||||||
*/
|
*/
|
||||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
if (this.effects.includes(pokemon.status?.effect)) {
|
if (pokemon.status && this.effects.includes(pokemon.status.effect)) {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2705,7 +2754,7 @@ export class IncrementMovePriorityAbAttr extends AbAttr {
|
|||||||
export class IgnoreContactAbAttr extends AbAttr { }
|
export class IgnoreContactAbAttr extends AbAttr { }
|
||||||
|
|
||||||
export class PreWeatherEffectAbAttr extends AbAttr {
|
export class PreWeatherEffectAbAttr extends AbAttr {
|
||||||
applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather | null, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2736,7 +2785,7 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
|
|||||||
constructor(affectsImmutable?: boolean) {
|
constructor(affectsImmutable?: boolean) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.affectsImmutable = affectsImmutable;
|
this.affectsImmutable = affectsImmutable!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
@ -2787,7 +2836,7 @@ function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
||||||
return weatherType && weatherTypes.indexOf(weatherType) > -1;
|
return !!weatherType && weatherTypes.indexOf(weatherType) > -1;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2796,15 +2845,15 @@ function getAnticipationCondition(): AbAttrCondition {
|
|||||||
for (const opponent of pokemon.getOpponents()) {
|
for (const opponent of pokemon.getOpponents()) {
|
||||||
for (const move of opponent.moveset) {
|
for (const move of opponent.moveset) {
|
||||||
// move is super effective
|
// move is super effective
|
||||||
if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, opponent, true) >= 2) {
|
if (move!.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move!.getMove().type, opponent, true) >= 2) { // TODO: is this bang correct?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// move is a OHKO
|
// move is a OHKO
|
||||||
if (move.getMove().hasAttr(OneHitKOAttr)) {
|
if (move!.getMove().hasAttr(OneHitKOAttr)) { // TODO: is this bang correct?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// edge case for hidden power, type is computed
|
// edge case for hidden power, type is computed
|
||||||
if (move.getMove().id === Moves.HIDDEN_POWER) {
|
if (move!.getMove().id === Moves.HIDDEN_POWER) { // TODO: is this bang correct?
|
||||||
const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1)
|
const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1)
|
||||||
+(opponent.ivs[Stat.ATK] & 1) * 2
|
+(opponent.ivs[Stat.ATK] & 1) * 2
|
||||||
+(opponent.ivs[Stat.DEF] & 1) * 4
|
+(opponent.ivs[Stat.DEF] & 1) * 4
|
||||||
@ -2852,21 +2901,21 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
|
|||||||
let movePower = 0;
|
let movePower = 0;
|
||||||
for (const opponent of pokemon.getOpponents()) {
|
for (const opponent of pokemon.getOpponents()) {
|
||||||
for (const move of opponent.moveset) {
|
for (const move of opponent.moveset) {
|
||||||
if (move.getMove() instanceof StatusMove) {
|
if (move!.getMove() instanceof StatusMove) { // TODO: is this bang correct?
|
||||||
movePower = 1;
|
movePower = 1;
|
||||||
} else if (move.getMove().hasAttr(OneHitKOAttr)) {
|
} else if (move!.getMove().hasAttr(OneHitKOAttr)) { // TODO: is this bang correct?
|
||||||
movePower = 150;
|
movePower = 150;
|
||||||
} else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) {
|
} else if (move!.getMove().id === Moves.COUNTER || move!.getMove().id === Moves.MIRROR_COAT || move!.getMove().id === Moves.METAL_BURST) { // TODO: are those bangs correct?
|
||||||
movePower = 120;
|
movePower = 120;
|
||||||
} else if (move.getMove().power === -1) {
|
} else if (move!.getMove().power === -1) { // TODO: is this bang correct?
|
||||||
movePower = 80;
|
movePower = 80;
|
||||||
} else {
|
} else {
|
||||||
movePower = move.getMove().power;
|
movePower = move!.getMove().power; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movePower > maxPowerSeen) {
|
if (movePower > maxPowerSeen) {
|
||||||
maxPowerSeen = movePower;
|
maxPowerSeen = movePower;
|
||||||
maxMove = move.getName();
|
maxMove = move!.getName(); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2927,7 +2976,7 @@ export class PostWeatherLapseAbAttr extends AbAttr {
|
|||||||
this.weatherTypes = weatherTypes;
|
this.weatherTypes = weatherTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean | Promise<boolean> {
|
applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather | null, args: any[]): boolean | Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3010,7 +3059,7 @@ export class PostTerrainChangeAddBattlerTagAttr extends PostTerrainChangeAbAttr
|
|||||||
function getTerrainCondition(...terrainTypes: TerrainType[]): AbAttrCondition {
|
function getTerrainCondition(...terrainTypes: TerrainType[]): AbAttrCondition {
|
||||||
return (pokemon: Pokemon) => {
|
return (pokemon: Pokemon) => {
|
||||||
const terrainType = pokemon.scene.arena.terrain?.terrainType;
|
const terrainType = pokemon.scene.arena.terrain?.terrainType;
|
||||||
return terrainType && terrainTypes.indexOf(terrainType) > -1;
|
return !!terrainType && terrainTypes.indexOf(terrainType) > -1;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3042,7 +3091,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
|
|||||||
* @returns Returns true if healed from status, false if not
|
* @returns Returns true if healed from status, false if not
|
||||||
*/
|
*/
|
||||||
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise<boolean> {
|
||||||
if (this.effects.includes(pokemon.status?.effect)) {
|
if (pokemon.status && this.effects.includes(pokemon.status.effect)) {
|
||||||
if (!pokemon.isFullHp()) {
|
if (!pokemon.isFullHp()) {
|
||||||
const scene = pokemon.scene;
|
const scene = pokemon.scene;
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
@ -3278,7 +3327,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr {
|
|||||||
*/
|
*/
|
||||||
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
const lastUsed = pokemon.scene.currentBattle.lastUsedPokeball;
|
const lastUsed = pokemon.scene.currentBattle.lastUsedPokeball;
|
||||||
if (lastUsed !== null && pokemon.isPlayer) {
|
if (lastUsed !== null && !!pokemon.isPlayer) {
|
||||||
pokemon.scene.pokeballCounts[lastUsed]++;
|
pokemon.scene.pokeballCounts[lastUsed]++;
|
||||||
pokemon.scene.currentBattle.lastUsedPokeball = null;
|
pokemon.scene.currentBattle.lastUsedPokeball = null;
|
||||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:fetchBall", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokeballName: getPokeballName(lastUsed) }));
|
pokemon.scene.queueMessage(i18next.t("abilityTriggers:fetchBall", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokeballName: getPokeballName(lastUsed) }));
|
||||||
@ -3559,7 +3608,8 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
|||||||
const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot;
|
const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot;
|
||||||
if (postBattleLoot.length) {
|
if (postBattleLoot.length) {
|
||||||
const randItem = Utils.randSeedItem(postBattleLoot);
|
const randItem = Utils.randSeedItem(postBattleLoot);
|
||||||
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) {
|
//@ts-ignore - TODO see below
|
||||||
|
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { // TODO: fix. This is a promise!?
|
||||||
postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1);
|
postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1);
|
||||||
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: randItem.type.name }));
|
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: randItem.type.name }));
|
||||||
return true;
|
return true;
|
||||||
@ -3591,7 +3641,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
|
|||||||
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
||||||
*/
|
*/
|
||||||
applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
const weatherType = pokemon.scene.arena.weather.weatherType;
|
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
||||||
let turnOffWeather = false;
|
let turnOffWeather = false;
|
||||||
|
|
||||||
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
|
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
|
||||||
@ -4063,7 +4113,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
|
|||||||
const turnCommand =
|
const turnCommand =
|
||||||
pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
||||||
const isCommandFight = turnCommand?.command === Command.FIGHT;
|
const isCommandFight = turnCommand?.command === Command.FIGHT;
|
||||||
const move = allMoves[turnCommand.move?.move];
|
const move = turnCommand?.move?.move ?allMoves[turnCommand.move.move] : null;
|
||||||
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
|
const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL;
|
||||||
|
|
||||||
if (isCommandFight && isDamageMove) {
|
if (isCommandFight && isDamageMove) {
|
||||||
@ -4082,14 +4132,14 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
|
|||||||
|
|
||||||
async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
||||||
attrType: Constructor<TAttr>,
|
attrType: Constructor<TAttr>,
|
||||||
pokemon: Pokemon,
|
pokemon: Pokemon | null,
|
||||||
applyFunc: AbAttrApplyFunc<TAttr>,
|
applyFunc: AbAttrApplyFunc<TAttr>,
|
||||||
args: any[],
|
args: any[],
|
||||||
showAbilityInstant: boolean = false,
|
showAbilityInstant: boolean = false,
|
||||||
quiet: boolean = false,
|
quiet: boolean = false,
|
||||||
) {
|
) {
|
||||||
for (const passive of [false, true]) {
|
for (const passive of [false, true]) {
|
||||||
if (!pokemon.canApplyAbility(passive)) {
|
if (!pokemon?.canApplyAbility(passive)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4137,7 +4187,7 @@ async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyAbAttrs(attrType: Constructor<AbAttr>, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
export function applyAbAttrs(attrType: Constructor<AbAttr>, pokemon: Pokemon, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<AbAttr>(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args);
|
return applyAbAttrsInternal<AbAttr>(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4147,13 +4197,13 @@ export function applyPostBattleInitAbAttrs(attrType: Constructor<PostBattleInitA
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreDefendAbAttrs(attrType: Constructor<PreDefendAbAttr>,
|
export function applyPreDefendAbAttrs(attrType: Constructor<PreDefendAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise<void> {
|
||||||
const simulated = args.length > 1 && args[1];
|
const simulated = args.length > 1 && args[1];
|
||||||
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, simulated);
|
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, simulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostDefendAbAttrs(attrType: Constructor<PostDefendAbAttr>,
|
export function applyPostDefendAbAttrs(attrType: Constructor<PostDefendAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostDefendAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4183,12 +4233,12 @@ export function applyFieldBattleStatMultiplierAbAttrs(attrType: Constructor<Fiel
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreAttackAbAttrs(attrType: Constructor<PreAttackAbAttr>,
|
export function applyPreAttackAbAttrs(attrType: Constructor<PreAttackAbAttr>,
|
||||||
pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, defender: Pokemon | null, move: Move, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
|
return applyAbAttrsInternal<PreAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostAttackAbAttrs(attrType: Constructor<PostAttackAbAttr>,
|
export function applyPostAttackAbAttrs(attrType: Constructor<PostAttackAbAttr>,
|
||||||
pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args);
|
return applyAbAttrsInternal<PostAttackAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4213,7 +4263,7 @@ export function applyPreSwitchOutAbAttrs(attrType: Constructor<PreSwitchOutAbAtt
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreStatChangeAbAttrs(attrType: Constructor<PreStatChangeAbAttr>,
|
export function applyPreStatChangeAbAttrs(attrType: Constructor<PreStatChangeAbAttr>,
|
||||||
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon | null, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
return applyAbAttrsInternal<PreStatChangeAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4223,7 +4273,7 @@ export function applyPostStatChangeAbAttrs(attrType: Constructor<PostStatChangeA
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreSetStatusAbAttrs(attrType: Constructor<PreSetStatusAbAttr>,
|
export function applyPreSetStatusAbAttrs(attrType: Constructor<PreSetStatusAbAttr>,
|
||||||
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
const simulated = args.length > 1 && args[1];
|
const simulated = args.length > 1 && args[1];
|
||||||
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, !simulated);
|
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, !simulated);
|
||||||
}
|
}
|
||||||
@ -4234,7 +4284,7 @@ export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor<PreApplyBat
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreWeatherEffectAbAttrs(attrType: Constructor<PreWeatherEffectAbAttr>,
|
export function applyPreWeatherEffectAbAttrs(attrType: Constructor<PreWeatherEffectAbAttr>,
|
||||||
pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, weather: Weather | null, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreWeatherDamageAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, true);
|
return applyAbAttrsInternal<PreWeatherDamageAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4249,7 +4299,7 @@ export function applyPostWeatherChangeAbAttrs(attrType: Constructor<PostWeatherC
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostWeatherLapseAbAttrs(attrType: Constructor<PostWeatherLapseAbAttr>,
|
export function applyPostWeatherLapseAbAttrs(attrType: Constructor<PostWeatherLapseAbAttr>,
|
||||||
pokemon: Pokemon, weather: Weather, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, weather: Weather | null, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostWeatherLapseAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args);
|
return applyAbAttrsInternal<PostWeatherLapseAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4538,8 +4588,8 @@ export function initAbilities() {
|
|||||||
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1)
|
.attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.RIVALRY, 4)
|
new Ability(Abilities.RIVALRY, 4)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender === target.gender, 1.25, true)
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user?.gender !== Gender.GENDERLESS && target?.gender !== Gender.GENDERLESS && user?.gender === target?.gender, 1.25, true)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender !== target.gender, 0.75),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user?.gender !== Gender.GENDERLESS && target?.gender !== Gender.GENDERLESS && user?.gender !== target?.gender, 0.75),
|
||||||
new Ability(Abilities.STEADFAST, 4)
|
new Ability(Abilities.STEADFAST, 4)
|
||||||
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
|
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
|
||||||
new Ability(Abilities.SNOW_CLOAK, 4)
|
new Ability(Abilities.SNOW_CLOAK, 4)
|
||||||
@ -4629,7 +4679,8 @@ export function initAbilities() {
|
|||||||
.attr(IgnoreOpponentStatChangesAbAttr)
|
.attr(IgnoreOpponentStatChangesAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.TINTED_LENS, 4)
|
new Ability(Abilities.TINTED_LENS, 4)
|
||||||
.attr(DamageBoostAbAttr, 2, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) <= 0.5),
|
//@ts-ignore
|
||||||
|
.attr(DamageBoostAbAttr, 2, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) <= 0.5), // TODO: fix TS issues
|
||||||
new Ability(Abilities.FILTER, 4)
|
new Ability(Abilities.FILTER, 4)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
|
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -4711,9 +4762,9 @@ export function initAbilities() {
|
|||||||
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.isFullHp(), 0.5)
|
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.isFullHp(), 0.5)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.TOXIC_BOOST, 5)
|
new Ability(Abilities.TOXIC_BOOST, 5)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.PHYSICAL && (user.status?.effect === StatusEffect.POISON || user.status?.effect === StatusEffect.TOXIC), 1.5),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.PHYSICAL && (user?.status?.effect === StatusEffect.POISON || user?.status?.effect === StatusEffect.TOXIC), 1.5),
|
||||||
new Ability(Abilities.FLARE_BOOST, 5)
|
new Ability(Abilities.FLARE_BOOST, 5)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.SPECIAL && user.status?.effect === StatusEffect.BURN, 1.5),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.SPECIAL && user?.status?.effect === StatusEffect.BURN, 1.5),
|
||||||
new Ability(Abilities.HARVEST, 5)
|
new Ability(Abilities.HARVEST, 5)
|
||||||
.attr(
|
.attr(
|
||||||
PostTurnLootAbAttr,
|
PostTurnLootAbAttr,
|
||||||
@ -4746,7 +4797,8 @@ export function initAbilities() {
|
|||||||
.attr(WonderSkinAbAttr)
|
.attr(WonderSkinAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.ANALYTIC, 5)
|
new Ability(Abilities.ANALYTIC, 5)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3),
|
//@ts-ignore
|
||||||
|
.attr(MovePowerBoostAbAttr, (user, target, move) => !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3), // TODO fix TS issues
|
||||||
new Ability(Abilities.ILLUSION, 5)
|
new Ability(Abilities.ILLUSION, 5)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
@ -4896,7 +4948,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.WATER_COMPACTION, 7)
|
new Ability(Abilities.WATER_COMPACTION, 7)
|
||||||
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
|
.attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2),
|
||||||
new Ability(Abilities.MERCILESS, 7)
|
new Ability(Abilities.MERCILESS, 7)
|
||||||
.attr(ConditionalCritAbAttr, (user, target, move) => target.status?.effect === StatusEffect.TOXIC || target.status?.effect === StatusEffect.POISON),
|
.attr(ConditionalCritAbAttr, (user, target, move) => target?.status?.effect === StatusEffect.TOXIC || target?.status?.effect === StatusEffect.POISON),
|
||||||
new Ability(Abilities.SHIELDS_DOWN, 7)
|
new Ability(Abilities.SHIELDS_DOWN, 7)
|
||||||
.attr(PostBattleInitFormChangeAbAttr, () => 0)
|
.attr(PostBattleInitFormChangeAbAttr, () => 0)
|
||||||
.attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
|
.attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0))
|
||||||
@ -4908,7 +4960,8 @@ export function initAbilities() {
|
|||||||
.bypassFaint()
|
.bypassFaint()
|
||||||
.partial(),
|
.partial(),
|
||||||
new Ability(Abilities.STAKEOUT, 7)
|
new Ability(Abilities.STAKEOUT, 7)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2),
|
//@ts-ignore
|
||||||
|
.attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2), // TODO: fix TS issues
|
||||||
new Ability(Abilities.WATER_BUBBLE, 7)
|
new Ability(Abilities.WATER_BUBBLE, 7)
|
||||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5)
|
||||||
.attr(MoveTypePowerBoostAbAttr, Type.WATER, 2)
|
.attr(MoveTypePowerBoostAbAttr, Type.WATER, 2)
|
||||||
@ -5048,7 +5101,8 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.PRISM_ARMOR, 7)
|
new Ability(Abilities.PRISM_ARMOR, 7)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75),
|
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75),
|
||||||
new Ability(Abilities.NEUROFORCE, 7)
|
new Ability(Abilities.NEUROFORCE, 7)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25),
|
//@ts-ignore
|
||||||
|
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25), // TODO: fix TS issues
|
||||||
new Ability(Abilities.INTREPID_SWORD, 8)
|
new Ability(Abilities.INTREPID_SWORD, 8)
|
||||||
.attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true)
|
.attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true)
|
||||||
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
|
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
|
||||||
@ -5073,7 +5127,9 @@ export function initAbilities() {
|
|||||||
.attr(UnsuppressableAbilityAbAttr)
|
.attr(UnsuppressableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
.attr(NoFusionAbilityAbAttr)
|
.attr(NoFusionAbilityAbAttr)
|
||||||
.unimplemented(),
|
.attr(UncopiableAbilityAbAttr)
|
||||||
|
.attr(UnswappableAbilityAbAttr)
|
||||||
|
.attr(PostDefendGulpMissileAbAttr),
|
||||||
new Ability(Abilities.STALWART, 8)
|
new Ability(Abilities.STALWART, 8)
|
||||||
.attr(BlockRedirectAbAttr),
|
.attr(BlockRedirectAbAttr),
|
||||||
new Ability(Abilities.STEAM_ENGINE, 8)
|
new Ability(Abilities.STEAM_ENGINE, 8)
|
||||||
@ -5083,7 +5139,7 @@ export function initAbilities() {
|
|||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.SOUND_BASED), 0.5)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.hasFlag(MoveFlags.SOUND_BASED), 0.5)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SAND_SPIT, 8)
|
new Ability(Abilities.SAND_SPIT, 8)
|
||||||
.attr(PostDefendWeatherChangeAbAttr, WeatherType.SANDSTORM),
|
.attr(PostDefendWeatherChangeAbAttr, WeatherType.SANDSTORM, (target, user, move) => move.category !== MoveCategory.STATUS),
|
||||||
new Ability(Abilities.ICE_SCALES, 8)
|
new Ability(Abilities.ICE_SCALES, 8)
|
||||||
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.SPECIAL, 0.5)
|
.attr(ReceivedMoveDamageMultiplierAbAttr, (target, user, move) => move.category === MoveCategory.SPECIAL, 0.5)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -5131,8 +5187,10 @@ export function initAbilities() {
|
|||||||
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
.attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.HUNGER_SWITCH, 8)
|
new Ability(Abilities.HUNGER_SWITCH, 8)
|
||||||
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1)
|
//@ts-ignore
|
||||||
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0)
|
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1) // TODO: fix ts-ignore
|
||||||
|
//@ts-ignore
|
||||||
|
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0) // TODO: fix ts-ignore
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
|
@ -25,12 +25,12 @@ export enum ArenaTagSide {
|
|||||||
export abstract class ArenaTag {
|
export abstract class ArenaTag {
|
||||||
public tagType: ArenaTagType;
|
public tagType: ArenaTagType;
|
||||||
public turnCount: integer;
|
public turnCount: integer;
|
||||||
public sourceMove: Moves;
|
public sourceMove?: Moves;
|
||||||
public sourceId: integer;
|
public sourceId?: integer;
|
||||||
public side: ArenaTagSide;
|
public side: ArenaTagSide;
|
||||||
|
|
||||||
|
|
||||||
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId?: integer, side: ArenaTagSide = ArenaTagSide.BOTH) {
|
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId?: integer, side: ArenaTagSide = ArenaTagSide.BOTH) {
|
||||||
this.tagType = tagType;
|
this.tagType = tagType;
|
||||||
this.turnCount = turnCount;
|
this.turnCount = turnCount;
|
||||||
this.sourceMove = sourceMove;
|
this.sourceMove = sourceMove;
|
||||||
@ -56,7 +56,7 @@ export abstract class ArenaTag {
|
|||||||
return this.turnCount < 1 || !!(--this.turnCount);
|
return this.turnCount < 1 || !!(--this.turnCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoveName(): string {
|
getMoveName(): string | null {
|
||||||
return this.sourceMove
|
return this.sourceMove
|
||||||
? allMoves[this.sourceMove].name
|
? allMoves[this.sourceMove].name
|
||||||
: null;
|
: null;
|
||||||
@ -75,9 +75,14 @@ export class MistTag extends ArenaTag {
|
|||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
super.onAdd(arena);
|
super.onAdd(arena);
|
||||||
|
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
if (this.sourceId) {
|
||||||
if (!quiet) {
|
const source = arena.scene.getPokemonById(this.sourceId);
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
|
||||||
|
if (!quiet && source) {
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||||
|
} else if (!quiet) {
|
||||||
|
console.warn("Failed to get source for MistTag onAdd");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,8 +285,14 @@ class MatBlockTag extends ConditionalProtectTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena) {
|
onAdd(arena: Arena) {
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
if (this.sourceId) {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
const source = arena.scene.getPokemonById(this.sourceId);
|
||||||
|
if (source) {
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to get source for MatBlockTag onAdd");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,6 +314,39 @@ class CraftyShieldTag extends ConditionalProtectTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Lucky_Chant_(move) Lucky Chant}.
|
||||||
|
* Prevents critical hits against the tag's side.
|
||||||
|
*/
|
||||||
|
export class NoCritTag extends ArenaTag {
|
||||||
|
/**
|
||||||
|
* Constructor method for the NoCritTag class
|
||||||
|
* @param turnCount `integer` the number of turns this effect lasts
|
||||||
|
* @param sourceMove {@linkcode Moves} the move that created this effect
|
||||||
|
* @param sourceId `integer` the ID of the {@linkcode Pokemon} that created this effect
|
||||||
|
* @param side {@linkcode ArenaTagSide} the side to which this effect belongs
|
||||||
|
*/
|
||||||
|
constructor(turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide) {
|
||||||
|
super(ArenaTagType.NO_CRIT, turnCount, sourceMove, sourceId, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Queues a message upon adding this effect to the field */
|
||||||
|
onAdd(arena: Arena): void {
|
||||||
|
arena.scene.queueMessage(i18next.t(`arenaTag:noCritOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : "Enemy"}`, {
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Queues a message upon removing this effect from the field */
|
||||||
|
onRemove(arena: Arena): void {
|
||||||
|
const source = arena.scene.getPokemonById(this.sourceId!); // TODO: is this bang correct?
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:noCritOnRemove", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(source ?? undefined),
|
||||||
|
moveName: this.getMoveName()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Wish_(move) Wish}.
|
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Wish_(move) Wish}.
|
||||||
* Heals the Pokémon in the user's position the turn after Wish is used.
|
* Heals the Pokémon in the user's position the turn after Wish is used.
|
||||||
@ -317,10 +361,16 @@ class WishTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena): void {
|
onAdd(arena: Arena): void {
|
||||||
const user = arena.scene.getPokemonById(this.sourceId);
|
if (this.sourceId) {
|
||||||
this.battlerIndex = user.getBattlerIndex();
|
const user = arena.scene.getPokemonById(this.sourceId);
|
||||||
this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) });
|
if (user) {
|
||||||
this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1);
|
this.battlerIndex = user.getBattlerIndex();
|
||||||
|
this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) });
|
||||||
|
this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1);
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to get source for WishTag onAdd");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(arena: Arena): void {
|
onRemove(arena: Arena): void {
|
||||||
@ -461,8 +511,8 @@ class SpikesTag extends ArenaTrapTag {
|
|||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
super.onAdd(arena);
|
super.onAdd(arena);
|
||||||
|
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||||
if (!quiet) {
|
if (!quiet && source) {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:spikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
arena.scene.queueMessage(i18next.t("arenaTag:spikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,8 +556,8 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
|||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
super.onAdd(arena);
|
super.onAdd(arena);
|
||||||
|
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||||
if (!quiet) {
|
if (!quiet && source) {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:toxicSpikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
arena.scene.queueMessage(i18next.t("arenaTag:toxicSpikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,7 +606,7 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
|||||||
class DelayedAttackTag extends ArenaTag {
|
class DelayedAttackTag extends ArenaTag {
|
||||||
public targetIndex: BattlerIndex;
|
public targetIndex: BattlerIndex;
|
||||||
|
|
||||||
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, targetIndex: BattlerIndex) {
|
constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: integer, targetIndex: BattlerIndex) {
|
||||||
super(tagType, 3, sourceMove, sourceId);
|
super(tagType, 3, sourceMove, sourceId);
|
||||||
|
|
||||||
this.targetIndex = targetIndex;
|
this.targetIndex = targetIndex;
|
||||||
@ -566,7 +616,7 @@ class DelayedAttackTag extends ArenaTag {
|
|||||||
const ret = super.lapse(arena);
|
const ret = super.lapse(arena);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
arena.scene.unshiftPhase(new MoveEffectPhase(arena.scene, this.sourceId, [ this.targetIndex ], new PokemonMove(this.sourceMove, 0, 0, true)));
|
arena.scene.unshiftPhase(new MoveEffectPhase(arena.scene, this.sourceId!, [ this.targetIndex ], new PokemonMove(this.sourceMove!, 0, 0, true))); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -588,8 +638,8 @@ class StealthRockTag extends ArenaTrapTag {
|
|||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
super.onAdd(arena);
|
super.onAdd(arena);
|
||||||
|
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||||
if (!quiet) {
|
if (!quiet && source) {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:stealthRockOnAdd", { opponentDesc: source.getOpponentDescriptor() }));
|
arena.scene.queueMessage(i18next.t("arenaTag:stealthRockOnAdd", { opponentDesc: source.getOpponentDescriptor() }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,7 +647,7 @@ class StealthRockTag extends ArenaTrapTag {
|
|||||||
getDamageHpRatio(pokemon: Pokemon): number {
|
getDamageHpRatio(pokemon: Pokemon): number {
|
||||||
const effectiveness = pokemon.getAttackTypeEffectiveness(Type.ROCK, undefined, true);
|
const effectiveness = pokemon.getAttackTypeEffectiveness(Type.ROCK, undefined, true);
|
||||||
|
|
||||||
let damageHpRatio: number;
|
let damageHpRatio: number = 0;
|
||||||
|
|
||||||
switch (effectiveness) {
|
switch (effectiveness) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -663,8 +713,8 @@ class StickyWebTag extends ArenaTrapTag {
|
|||||||
|
|
||||||
onAdd(arena: Arena, quiet: boolean = false): void {
|
onAdd(arena: Arena, quiet: boolean = false): void {
|
||||||
super.onAdd(arena);
|
super.onAdd(arena);
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||||
if (!quiet) {
|
if (!quiet && source) {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:stickyWebOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
arena.scene.queueMessage(i18next.t("arenaTag:stickyWebOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,7 +752,10 @@ export class TrickRoomTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAdd(arena: Arena): void {
|
onAdd(arena: Arena): void {
|
||||||
arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(arena.scene.getPokemonById(this.sourceId)) }));
|
const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null;
|
||||||
|
if (source) {
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(arena: Arena): void {
|
onRemove(arena: Arena): void {
|
||||||
@ -749,8 +802,8 @@ class TailwindTag extends ArenaTag {
|
|||||||
arena.scene.queueMessage(i18next.t(`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
arena.scene.queueMessage(i18next.t(`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const source = arena.scene.getPokemonById(this.sourceId);
|
const source = arena.scene.getPokemonById(this.sourceId!); //TODO: this bang is questionable!
|
||||||
const party = source.isPlayer() ? source.scene.getPlayerField() : source.scene.getEnemyField();
|
const party = (source?.isPlayer() ? source.scene.getPlayerField() : source?.scene.getEnemyField()) ?? [];
|
||||||
|
|
||||||
for (const pokemon of party) {
|
for (const pokemon of party) {
|
||||||
// Apply the CHARGED tag to party members with the WIND_POWER ability
|
// Apply the CHARGED tag to party members with the WIND_POWER ability
|
||||||
@ -791,7 +844,7 @@ class HappyHourTag extends ArenaTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag {
|
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case ArenaTagType.MIST:
|
case ArenaTagType.MIST:
|
||||||
return new MistTag(turnCount, sourceId, side);
|
return new MistTag(turnCount, sourceId, side);
|
||||||
@ -803,6 +856,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new MatBlockTag(sourceId, side);
|
return new MatBlockTag(sourceId, side);
|
||||||
case ArenaTagType.CRAFTY_SHIELD:
|
case ArenaTagType.CRAFTY_SHIELD:
|
||||||
return new CraftyShieldTag(sourceId, side);
|
return new CraftyShieldTag(sourceId, side);
|
||||||
|
case ArenaTagType.NO_CRIT:
|
||||||
|
return new NoCritTag(turnCount, sourceMove!, sourceId, side); // TODO: is this bang correct?
|
||||||
case ArenaTagType.MUD_SPORT:
|
case ArenaTagType.MUD_SPORT:
|
||||||
return new MudSportTag(turnCount, sourceId);
|
return new MudSportTag(turnCount, sourceId);
|
||||||
case ArenaTagType.WATER_SPORT:
|
case ArenaTagType.WATER_SPORT:
|
||||||
@ -813,7 +868,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new ToxicSpikesTag(sourceId, side);
|
return new ToxicSpikesTag(sourceId, side);
|
||||||
case ArenaTagType.FUTURE_SIGHT:
|
case ArenaTagType.FUTURE_SIGHT:
|
||||||
case ArenaTagType.DOOM_DESIRE:
|
case ArenaTagType.DOOM_DESIRE:
|
||||||
return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex);
|
return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex!); // TODO:questionable bang
|
||||||
case ArenaTagType.WISH:
|
case ArenaTagType.WISH:
|
||||||
return new WishTag(turnCount, sourceId, side);
|
return new WishTag(turnCount, sourceId, side);
|
||||||
case ArenaTagType.STEALTH_ROCK:
|
case ArenaTagType.STEALTH_ROCK:
|
||||||
@ -834,5 +889,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new TailwindTag(turnCount, sourceId, side);
|
return new TailwindTag(turnCount, sourceId, side);
|
||||||
case ArenaTagType.HAPPY_HOUR:
|
case ArenaTagType.HAPPY_HOUR:
|
||||||
return new HappyHourTag(turnCount, sourceId, side);
|
return new HappyHourTag(turnCount, sourceId, side);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//import { battleAnimRawData } from "./battle-anim-raw-data";
|
//import { battleAnimRawData } from "./battle-anim-raw-data";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { AttackMove, ChargeAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
|
import { AttackMove, BeakBlastHeaderAttr, ChargeAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
|
||||||
import Pokemon from "../field/pokemon";
|
import Pokemon from "../field/pokemon";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
@ -128,7 +128,7 @@ export class AnimConfig {
|
|||||||
for (const fte of Object.keys(frameTimedEvents)) {
|
for (const fte of Object.keys(frameTimedEvents)) {
|
||||||
const timedEvents: AnimTimedEvent[] = [];
|
const timedEvents: AnimTimedEvent[] = [];
|
||||||
for (const te of frameTimedEvents[fte]) {
|
for (const te of frameTimedEvents[fte]) {
|
||||||
let timedEvent: AnimTimedEvent;
|
let timedEvent: AnimTimedEvent | undefined;
|
||||||
switch (te.eventType) {
|
switch (te.eventType) {
|
||||||
case "AnimTimedSoundEvent":
|
case "AnimTimedSoundEvent":
|
||||||
timedEvent = new AnimTimedSoundEvent(te.frameIndex, te.resourceName, te);
|
timedEvent = new AnimTimedSoundEvent(te.frameIndex, te.resourceName, te);
|
||||||
@ -140,7 +140,8 @@ export class AnimConfig {
|
|||||||
timedEvent = new AnimTimedUpdateBgEvent(te.frameIndex, te.resourceName, te);
|
timedEvent = new AnimTimedUpdateBgEvent(te.frameIndex, te.resourceName, te);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
timedEvents.push(timedEvent);
|
|
||||||
|
timedEvent && timedEvents.push(timedEvent);
|
||||||
}
|
}
|
||||||
this.frameTimedEvents.set(parseInt(fte), timedEvents);
|
this.frameTimedEvents.set(parseInt(fte), timedEvents);
|
||||||
}
|
}
|
||||||
@ -330,7 +331,7 @@ class AnimTimedSoundEvent extends AnimTimedEvent {
|
|||||||
}
|
}
|
||||||
return Math.ceil((scene.sound.get(this.resourceName).totalDuration * 1000) / 33.33);
|
return Math.ceil((scene.sound.get(this.resourceName).totalDuration * 1000) / 33.33);
|
||||||
} else {
|
} else {
|
||||||
return Math.ceil((battleAnim.user.cry(soundConfig).totalDuration * 1000) / 33.33);
|
return Math.ceil((battleAnim.user!.cry(soundConfig).totalDuration * 1000) / 33.33); // TODO: is the bang behind user correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,15 +442,15 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const moveAnims = new Map<Moves, AnimConfig | [AnimConfig, AnimConfig]>();
|
export const moveAnims = new Map<Moves, AnimConfig | [AnimConfig, AnimConfig] | null>();
|
||||||
export const chargeAnims = new Map<ChargeAnim, AnimConfig | [AnimConfig, AnimConfig]>();
|
export const chargeAnims = new Map<ChargeAnim, AnimConfig | [AnimConfig, AnimConfig] | null>();
|
||||||
export const commonAnims = new Map<CommonAnim, AnimConfig>();
|
export const commonAnims = new Map<CommonAnim, AnimConfig>();
|
||||||
|
|
||||||
export function initCommonAnims(scene: BattleScene): Promise<void> {
|
export function initCommonAnims(scene: BattleScene): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
|
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
|
||||||
const commonAnimIds = Utils.getEnumValues(CommonAnim);
|
const commonAnimIds = Utils.getEnumValues(CommonAnim);
|
||||||
const commonAnimFetches = [];
|
const commonAnimFetches: Promise<Map<CommonAnim, AnimConfig>>[] = [];
|
||||||
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
for (let ca = 0; ca < commonAnimIds.length; ca++) {
|
||||||
const commonAnimId = commonAnimIds[ca];
|
const commonAnimId = commonAnimIds[ca];
|
||||||
commonAnimFetches.push(scene.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`)
|
commonAnimFetches.push(scene.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`)
|
||||||
@ -498,7 +499,9 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
|
|||||||
} else {
|
} else {
|
||||||
populateMoveAnim(move, ba);
|
populateMoveAnim(move, ba);
|
||||||
}
|
}
|
||||||
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] || allMoves[move].getAttrs(DelayedAttackAttr)[0];
|
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0]
|
||||||
|
|| allMoves[move].getAttrs(DelayedAttackAttr)[0]
|
||||||
|
|| allMoves[move].getAttrs(BeakBlastHeaderAttr)[0];
|
||||||
if (chargeAttr) {
|
if (chargeAttr) {
|
||||||
initMoveChargeAnim(scene, chargeAttr.chargeAnim).then(() => resolve());
|
initMoveChargeAnim(scene, chargeAttr.chargeAnim).then(() => resolve());
|
||||||
} else {
|
} else {
|
||||||
@ -569,10 +572,12 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo
|
|||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
|
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
|
||||||
for (const moveId of moveIds) {
|
for (const moveId of moveIds) {
|
||||||
const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0] || allMoves[moveId].getAttrs(DelayedAttackAttr)[0];
|
const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0]
|
||||||
|
|| allMoves[moveId].getAttrs(DelayedAttackAttr)[0]
|
||||||
|
|| allMoves[moveId].getAttrs(BeakBlastHeaderAttr)[0];
|
||||||
if (chargeAttr) {
|
if (chargeAttr) {
|
||||||
const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim);
|
const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim);
|
||||||
moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims[0]);
|
moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims![0]); // TODO: is the bang correct?
|
||||||
if (Array.isArray(moveChargeAnims)) {
|
if (Array.isArray(moveChargeAnims)) {
|
||||||
moveAnimations.push(moveChargeAnims[1]);
|
moveAnimations.push(moveChargeAnims[1]);
|
||||||
}
|
}
|
||||||
@ -668,21 +673,21 @@ interface SpriteCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BattleAnim {
|
export abstract class BattleAnim {
|
||||||
public user: Pokemon;
|
public user: Pokemon | null;
|
||||||
public target: Pokemon;
|
public target: Pokemon | null;
|
||||||
public sprites: Phaser.GameObjects.Sprite[];
|
public sprites: Phaser.GameObjects.Sprite[];
|
||||||
public bgSprite: Phaser.GameObjects.TileSprite | Phaser.GameObjects.Rectangle;
|
public bgSprite: Phaser.GameObjects.TileSprite | Phaser.GameObjects.Rectangle;
|
||||||
|
|
||||||
private srcLine: number[];
|
private srcLine: number[];
|
||||||
private dstLine: number[];
|
private dstLine: number[];
|
||||||
|
|
||||||
constructor(user: Pokemon, target: Pokemon) {
|
constructor(user?: Pokemon, target?: Pokemon) {
|
||||||
this.user = user;
|
this.user = user!; // TODO: is this bang correct?
|
||||||
this.target = target;
|
this.target = target!; // TODO: is this bang correct?
|
||||||
this.sprites = [];
|
this.sprites = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract getAnim(): AnimConfig;
|
abstract getAnim(): AnimConfig | null;
|
||||||
|
|
||||||
abstract isOppAnim(): boolean;
|
abstract isOppAnim(): boolean;
|
||||||
|
|
||||||
@ -705,12 +710,12 @@ export abstract class BattleAnim {
|
|||||||
const user = !isOppAnim ? this.user : this.target;
|
const user = !isOppAnim ? this.user : this.target;
|
||||||
const target = !isOppAnim ? this.target : this.user;
|
const target = !isOppAnim ? this.target : this.user;
|
||||||
|
|
||||||
const userInitialX = user.x;
|
const userInitialX = user!.x; // TODO: is this bang correct?
|
||||||
const userInitialY = user.y;
|
const userInitialY = user!.y; // TODO: is this bang correct?
|
||||||
const userHalfHeight = user.getSprite().displayHeight / 2;
|
const userHalfHeight = user!.getSprite().displayHeight! / 2; // TODO: is this bang correct?
|
||||||
const targetInitialX = target.x;
|
const targetInitialX = target!.x; // TODO: is this bang correct?
|
||||||
const targetInitialY = target.y;
|
const targetInitialY = target!.y; // TODO: is this bang correct?
|
||||||
const targetHalfHeight = target.getSprite().displayHeight / 2;
|
const targetHalfHeight = target!.getSprite().displayHeight! / 2; // TODO: is this bang correct?
|
||||||
|
|
||||||
let g = 0;
|
let g = 0;
|
||||||
let u = 0;
|
let u = 0;
|
||||||
@ -742,7 +747,7 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
const angle = -frame.angle;
|
const angle = -frame.angle;
|
||||||
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++;
|
||||||
ret.get(frame.target).set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle });
|
ret.get(frame.target)!.set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); // TODO: is the bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -750,10 +755,10 @@ export abstract class BattleAnim {
|
|||||||
|
|
||||||
play(scene: BattleScene, callback?: Function) {
|
play(scene: BattleScene, callback?: Function) {
|
||||||
const isOppAnim = this.isOppAnim();
|
const isOppAnim = this.isOppAnim();
|
||||||
const user = !isOppAnim ? this.user : this.target;
|
const user = !isOppAnim ? this.user! : this.target!; // TODO: are those bangs correct?
|
||||||
const target = !isOppAnim ? this.target : this.user;
|
const target = !isOppAnim ? this.target : this.user;
|
||||||
|
|
||||||
if (!target.isOnField()) {
|
if (!target?.isOnField()) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -781,7 +786,7 @@ export abstract class BattleAnim {
|
|||||||
targetSprite.setAlpha(1);
|
targetSprite.setAlpha(1);
|
||||||
targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ];
|
targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ];
|
||||||
targetSprite.setAngle(0);
|
targetSprite.setAngle(0);
|
||||||
if (!this.isHideUser()) {
|
if (!this.isHideUser() && userSprite) {
|
||||||
userSprite.setVisible(true);
|
userSprite.setVisible(true);
|
||||||
}
|
}
|
||||||
if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) {
|
if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) {
|
||||||
@ -814,20 +819,20 @@ export abstract class BattleAnim {
|
|||||||
this.srcLine = [ userFocusX, userFocusY, targetFocusX, targetFocusY ];
|
this.srcLine = [ userFocusX, userFocusY, targetFocusX, targetFocusY ];
|
||||||
this.dstLine = [ userInitialX, userInitialY, targetInitialX, targetInitialY ];
|
this.dstLine = [ userInitialX, userInitialY, targetInitialX, targetInitialY ];
|
||||||
|
|
||||||
let r = anim.frames.length;
|
let r = anim!.frames.length; // TODO: is this bang correct?
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
scene.tweens.addCounter({
|
scene.tweens.addCounter({
|
||||||
duration: Utils.getFrameMs(3),
|
duration: Utils.getFrameMs(3),
|
||||||
repeat: anim.frames.length,
|
repeat: anim!.frames.length, // TODO: is this bang correct?
|
||||||
onRepeat: () => {
|
onRepeat: () => {
|
||||||
if (!f) {
|
if (!f) {
|
||||||
userSprite.setVisible(false);
|
userSprite.setVisible(false);
|
||||||
targetSprite.setVisible(false);
|
targetSprite.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const spriteFrames = anim.frames[f];
|
const spriteFrames = anim!.frames[f]; // TODO: is the bang correcT?
|
||||||
const frameData = this.getGraphicFrameData(scene, anim.frames[f]);
|
const frameData = this.getGraphicFrameData(scene, anim!.frames[f]); // TODO: is the bang correct?
|
||||||
let u = 0;
|
let u = 0;
|
||||||
let t = 0;
|
let t = 0;
|
||||||
let g = 0;
|
let g = 0;
|
||||||
@ -840,9 +845,9 @@ export abstract class BattleAnim {
|
|||||||
const sprites = spriteCache[isUser ? AnimFrameTarget.USER : AnimFrameTarget.TARGET];
|
const sprites = spriteCache[isUser ? AnimFrameTarget.USER : AnimFrameTarget.TARGET];
|
||||||
const spriteSource = isUser ? userSprite : targetSprite;
|
const spriteSource = isUser ? userSprite : targetSprite;
|
||||||
if ((isUser ? u : t) === sprites.length) {
|
if ((isUser ? u : t) === sprites.length) {
|
||||||
const sprite = scene.addPokemonSprite(isUser ? user : target, 0, 0, spriteSource.texture, spriteSource.frame.name, true);
|
const sprite = scene.addPokemonSprite(isUser ? user! : target, 0, 0, spriteSource!.texture, spriteSource!.frame.name, true); // TODO: are those bangs correct?
|
||||||
[ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = (isUser ? user : target).getSprite().pipelineData[k]);
|
[ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = (isUser ? user! : target).getSprite().pipelineData[k]); // TODO: are those bangs correct?
|
||||||
sprite.setPipelineData("spriteKey", (isUser ? user : target).getBattleSpriteKey());
|
sprite.setPipelineData("spriteKey", (isUser ? user! : target).getBattleSpriteKey());
|
||||||
sprite.setPipelineData("shiny", (isUser ? user : target).shiny);
|
sprite.setPipelineData("shiny", (isUser ? user : target).shiny);
|
||||||
sprite.setPipelineData("variant", (isUser ? user : target).variant);
|
sprite.setPipelineData("variant", (isUser ? user : target).variant);
|
||||||
sprite.setPipelineData("ignoreFieldPos", true);
|
sprite.setPipelineData("ignoreFieldPos", true);
|
||||||
@ -853,7 +858,7 @@ export abstract class BattleAnim {
|
|||||||
|
|
||||||
const spriteIndex = isUser ? u++ : t++;
|
const spriteIndex = isUser ? u++ : t++;
|
||||||
const pokemonSprite = sprites[spriteIndex];
|
const pokemonSprite = sprites[spriteIndex];
|
||||||
const graphicFrameData = frameData.get(frame.target).get(spriteIndex);
|
const graphicFrameData = frameData.get(frame.target)!.get(spriteIndex)!; // TODO: are the bangs correct?
|
||||||
pokemonSprite.setPosition(graphicFrameData.x, graphicFrameData.y - ((spriteSource.height / 2) * (spriteSource.parentContainer.scale - 1)));
|
pokemonSprite.setPosition(graphicFrameData.x, graphicFrameData.y - ((spriteSource.height / 2) * (spriteSource.parentContainer.scale - 1)));
|
||||||
|
|
||||||
pokemonSprite.setAngle(graphicFrameData.angle);
|
pokemonSprite.setAngle(graphicFrameData.angle);
|
||||||
@ -868,7 +873,7 @@ export abstract class BattleAnim {
|
|||||||
} else {
|
} else {
|
||||||
const sprites = spriteCache[AnimFrameTarget.GRAPHIC];
|
const sprites = spriteCache[AnimFrameTarget.GRAPHIC];
|
||||||
if (g === sprites.length) {
|
if (g === sprites.length) {
|
||||||
const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim.graphic, 1);
|
const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim!.graphic, 1); // TODO: is the bang correct?
|
||||||
sprites.push(newSprite);
|
sprites.push(newSprite);
|
||||||
scene.field.add(newSprite);
|
scene.field.add(newSprite);
|
||||||
spritePriorities.push(1);
|
spritePriorities.push(1);
|
||||||
@ -881,7 +886,7 @@ export abstract class BattleAnim {
|
|||||||
const setSpritePriority = (priority: integer) => {
|
const setSpritePriority = (priority: integer) => {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
case 0:
|
case 0:
|
||||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, scene.getEnemyPokemon() || scene.getPlayerPokemon());
|
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, scene.getEnemyPokemon() || scene.getPlayerPokemon()!); // TODO: is this bang correct?
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
|
||||||
@ -892,11 +897,11 @@ export abstract class BattleAnim {
|
|||||||
if (this.bgSprite) {
|
if (this.bgSprite) {
|
||||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite);
|
||||||
} else {
|
} else {
|
||||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user);
|
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AnimFocus.TARGET:
|
case AnimFocus.TARGET:
|
||||||
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target);
|
scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setSpritePriority(1);
|
setSpritePriority(1);
|
||||||
@ -906,10 +911,10 @@ export abstract class BattleAnim {
|
|||||||
case 3:
|
case 3:
|
||||||
switch (frame.focus) {
|
switch (frame.focus) {
|
||||||
case AnimFocus.USER:
|
case AnimFocus.USER:
|
||||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user);
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct?
|
||||||
break;
|
break;
|
||||||
case AnimFocus.TARGET:
|
case AnimFocus.TARGET:
|
||||||
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target);
|
scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct?
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setSpritePriority(1);
|
setSpritePriority(1);
|
||||||
@ -925,7 +930,7 @@ export abstract class BattleAnim {
|
|||||||
moveSprite.setFrame(frame.graphicFrame);
|
moveSprite.setFrame(frame.graphicFrame);
|
||||||
//console.log(AnimFocus[frame.focus]);
|
//console.log(AnimFocus[frame.focus]);
|
||||||
|
|
||||||
const graphicFrameData = frameData.get(frame.target).get(graphicIndex);
|
const graphicFrameData = frameData.get(frame.target)!.get(graphicIndex)!; // TODO: are those bangs correct?
|
||||||
moveSprite.setPosition(graphicFrameData.x, graphicFrameData.y);
|
moveSprite.setPosition(graphicFrameData.x, graphicFrameData.y);
|
||||||
moveSprite.setAngle(graphicFrameData.angle);
|
moveSprite.setAngle(graphicFrameData.angle);
|
||||||
moveSprite.setScale(graphicFrameData.scaleX, graphicFrameData.scaleY);
|
moveSprite.setScale(graphicFrameData.scaleX, graphicFrameData.scaleY);
|
||||||
@ -935,8 +940,8 @@ export abstract class BattleAnim {
|
|||||||
moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE);
|
moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anim.frameTimedEvents.has(f)) {
|
if (anim?.frameTimedEvents.has(f)) {
|
||||||
for (const event of anim.frameTimedEvents.get(f)) {
|
for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct?
|
||||||
r = Math.max((anim.frames.length - f) + event.execute(scene, this), r);
|
r = Math.max((anim.frames.length - f) + event.execute(scene, this), r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -980,16 +985,16 @@ export abstract class BattleAnim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CommonBattleAnim extends BattleAnim {
|
export class CommonBattleAnim extends BattleAnim {
|
||||||
public commonAnim: CommonAnim;
|
public commonAnim: CommonAnim | null;
|
||||||
|
|
||||||
constructor(commonAnim: CommonAnim, user: Pokemon, target?: Pokemon) {
|
constructor(commonAnim: CommonAnim | null, user: Pokemon, target?: Pokemon) {
|
||||||
super(user, target || user);
|
super(user, target || user);
|
||||||
|
|
||||||
this.commonAnim = commonAnim;
|
this.commonAnim = commonAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnim(): AnimConfig {
|
getAnim(): AnimConfig | null {
|
||||||
return commonAnims.get(this.commonAnim);
|
return this.commonAnim ? commonAnims.get(this.commonAnim)! : null; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
isOppAnim(): boolean {
|
isOppAnim(): boolean {
|
||||||
@ -1009,11 +1014,11 @@ export class MoveAnim extends BattleAnim {
|
|||||||
getAnim(): AnimConfig {
|
getAnim(): AnimConfig {
|
||||||
return moveAnims.get(this.move) instanceof AnimConfig
|
return moveAnims.get(this.move) instanceof AnimConfig
|
||||||
? moveAnims.get(this.move) as AnimConfig
|
? moveAnims.get(this.move) as AnimConfig
|
||||||
: moveAnims.get(this.move)[this.user.isPlayer() ? 0 : 1] as AnimConfig;
|
: moveAnims.get(this.move)![this.user?.isPlayer() ? 0 : 1] as AnimConfig; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
isOppAnim(): boolean {
|
isOppAnim(): boolean {
|
||||||
return !this.user.isPlayer() && Array.isArray(moveAnims.get(this.move));
|
return !this.user?.isPlayer() && Array.isArray(moveAnims.get(this.move));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected isHideUser(): boolean {
|
protected isHideUser(): boolean {
|
||||||
@ -1035,13 +1040,13 @@ export class MoveChargeAnim extends MoveAnim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isOppAnim(): boolean {
|
isOppAnim(): boolean {
|
||||||
return !this.user.isPlayer() && Array.isArray(chargeAnims.get(this.chargeAnim));
|
return !this.user?.isPlayer() && Array.isArray(chargeAnims.get(this.chargeAnim));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnim(): AnimConfig {
|
getAnim(): AnimConfig {
|
||||||
return chargeAnims.get(this.chargeAnim) instanceof AnimConfig
|
return chargeAnims.get(this.chargeAnim) instanceof AnimConfig
|
||||||
? chargeAnims.get(this.chargeAnim) as AnimConfig
|
? chargeAnims.get(this.chargeAnim) as AnimConfig
|
||||||
: chargeAnims.get(this.chargeAnim)[this.user.isPlayer() ? 0 : 1] as AnimConfig;
|
: chargeAnims.get(this.chargeAnim)![this.user?.isPlayer() ? 0 : 1] as AnimConfig; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1059,19 +1064,19 @@ export async function populateAnims() {
|
|||||||
moveNameToId[moveName] = move;
|
moveNameToId[moveName] = move;
|
||||||
}
|
}
|
||||||
|
|
||||||
const seNames = [];//(await fs.readdir('./public/audio/se/battle_anims/')).map(se => se.toString());
|
const seNames: string[] = [];//(await fs.readdir('./public/audio/se/battle_anims/')).map(se => se.toString());
|
||||||
|
|
||||||
const animsData = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1);
|
const animsData : any[] = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1); // TODO: add a proper type
|
||||||
for (let a = 0; a < animsData.length; a++) {
|
for (let a = 0; a < animsData.length; a++) {
|
||||||
const fields = animsData[a].split("@").slice(1);
|
const fields = animsData[a].split("@").slice(1);
|
||||||
|
|
||||||
const nameField = fields.find(f => f.startsWith("name: "));
|
const nameField = fields.find(f => f.startsWith("name: "));
|
||||||
|
|
||||||
let isOppMove: boolean;
|
let isOppMove: boolean | undefined;
|
||||||
let commonAnimId: CommonAnim;
|
let commonAnimId: CommonAnim | undefined;
|
||||||
let chargeAnimId: ChargeAnim;
|
let chargeAnimId: ChargeAnim | undefined;
|
||||||
if (!nameField.startsWith("name: Move:") && !(isOppMove = nameField.startsWith("name: OppMove:"))) {
|
if (!nameField.startsWith("name: Move:") && !(isOppMove = nameField.startsWith("name: OppMove:"))) {
|
||||||
const nameMatch = commonNamePattern.exec(nameField);
|
const nameMatch = commonNamePattern.exec(nameField)!; // TODO: is this bang correct?
|
||||||
const name = nameMatch[2].toLowerCase();
|
const name = nameMatch[2].toLowerCase();
|
||||||
if (commonAnimMatchNames.indexOf(name) > -1) {
|
if (commonAnimMatchNames.indexOf(name) > -1) {
|
||||||
commonAnimId = commonAnimIds[commonAnimMatchNames.indexOf(name)];
|
commonAnimId = commonAnimIds[commonAnimMatchNames.indexOf(name)];
|
||||||
@ -1128,14 +1133,14 @@ export async function populateAnims() {
|
|||||||
for (let t = 0; t < timingEntries.length; t++) {
|
for (let t = 0; t < timingEntries.length; t++) {
|
||||||
const timingData = timingEntries[t].replace(/\n/g, " ").replace(/[ ]{2,}/g, " ").replace(/[a-z]+: ! '', /ig, "").replace(/name: (.*?),/, "name: \"$1\",")
|
const timingData = timingEntries[t].replace(/\n/g, " ").replace(/[ ]{2,}/g, " ").replace(/[a-z]+: ! '', /ig, "").replace(/name: (.*?),/, "name: \"$1\",")
|
||||||
.replace(/flashColor: !ruby\/object:Color { alpha: ([\d\.]+), blue: ([\d\.]+), green: ([\d\.]+), red: ([\d\.]+)}/, "flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1");
|
.replace(/flashColor: !ruby\/object:Color { alpha: ([\d\.]+), blue: ([\d\.]+), green: ([\d\.]+), red: ([\d\.]+)}/, "flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1");
|
||||||
const frameIndex = parseInt(/frame: (\d+)/.exec(timingData)[1]);
|
const frameIndex = parseInt(/frame: (\d+)/.exec(timingData)![1]); // TODO: is the bang correct?
|
||||||
let resourceName = /name: "(.*?)"/.exec(timingData)[1].replace("''", "");
|
let resourceName = /name: "(.*?)"/.exec(timingData)![1].replace("''", ""); // TODO: is the bang correct?
|
||||||
const timingType = parseInt(/timingType: (\d)/.exec(timingData)[1]);
|
const timingType = parseInt(/timingType: (\d)/.exec(timingData)![1]); // TODO: is the bang correct?
|
||||||
let timedEvent: AnimTimedEvent;
|
let timedEvent: AnimTimedEvent | undefined;
|
||||||
switch (timingType) {
|
switch (timingType) {
|
||||||
case 0:
|
case 0:
|
||||||
if (resourceName && resourceName.indexOf(".") === -1) {
|
if (resourceName && resourceName.indexOf(".") === -1) {
|
||||||
let ext: string;
|
let ext: string | undefined;
|
||||||
[ "wav", "mp3", "m4a" ].every(e => {
|
[ "wav", "mp3", "m4a" ].every(e => {
|
||||||
if (seNames.indexOf(`${resourceName}.${e}`) > -1) {
|
if (seNames.indexOf(`${resourceName}.${e}`) > -1) {
|
||||||
ext = e;
|
ext = e;
|
||||||
@ -1162,7 +1167,7 @@ export async function populateAnims() {
|
|||||||
}
|
}
|
||||||
const propPattern = /([a-z]+): (.*?)(?:,|\})/ig;
|
const propPattern = /([a-z]+): (.*?)(?:,|\})/ig;
|
||||||
let propMatch: RegExpExecArray;
|
let propMatch: RegExpExecArray;
|
||||||
while ((propMatch = propPattern.exec(timingData))) {
|
while ((propMatch = propPattern.exec(timingData)!)) { // TODO: is this bang correct?
|
||||||
const prop = propMatch[1];
|
const prop = propMatch[1];
|
||||||
let value: any = propMatch[2];
|
let value: any = propMatch[2];
|
||||||
switch (prop) {
|
switch (prop) {
|
||||||
@ -1194,7 +1199,7 @@ export async function populateAnims() {
|
|||||||
if (!anim.frameTimedEvents.has(frameIndex)) {
|
if (!anim.frameTimedEvents.has(frameIndex)) {
|
||||||
anim.frameTimedEvents.set(frameIndex, []);
|
anim.frameTimedEvents.set(frameIndex, []);
|
||||||
}
|
}
|
||||||
anim.frameTimedEvents.get(frameIndex).push(timedEvent);
|
anim.frameTimedEvents.get(frameIndex)!.push(timedEvent); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "position":
|
case "position":
|
||||||
|
@ -8,7 +8,8 @@ export enum BattleStat {
|
|||||||
SPD,
|
SPD,
|
||||||
ACC,
|
ACC,
|
||||||
EVA,
|
EVA,
|
||||||
RAND
|
RAND,
|
||||||
|
HP
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBattleStatName(stat: BattleStat) {
|
export function getBattleStatName(stat: BattleStat) {
|
||||||
@ -27,6 +28,8 @@ export function getBattleStatName(stat: BattleStat) {
|
|||||||
return i18next.t("pokemonInfo:Stat.ACC");
|
return i18next.t("pokemonInfo:Stat.ACC");
|
||||||
case BattleStat.EVA:
|
case BattleStat.EVA:
|
||||||
return i18next.t("pokemonInfo:Stat.EVA");
|
return i18next.t("pokemonInfo:Stat.EVA");
|
||||||
|
case BattleStat.HP:
|
||||||
|
return i18next.t("pokemonInfo:Stat.HPStat");
|
||||||
default:
|
default:
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,11 @@ export class BattlerTag {
|
|||||||
public sourceMove: Moves;
|
public sourceMove: Moves;
|
||||||
public sourceId?: number;
|
public sourceId?: number;
|
||||||
|
|
||||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove: Moves, sourceId?: number) {
|
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove?: Moves, sourceId?: number) {
|
||||||
this.tagType = tagType;
|
this.tagType = tagType;
|
||||||
this.lapseTypes = Array.isArray(lapseType) ? lapseType : [ lapseType ];
|
this.lapseTypes = Array.isArray(lapseType) ? lapseType : [ lapseType ];
|
||||||
this.turnCount = turnCount;
|
this.turnCount = turnCount;
|
||||||
this.sourceMove = sourceMove;
|
this.sourceMove = sourceMove!; // TODO: is this bang correct?
|
||||||
this.sourceId = sourceId;
|
this.sourceId = sourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ export class BattlerTag {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoveName(): string {
|
getMoveName(): string | null {
|
||||||
return this.sourceMove
|
return this.sourceMove
|
||||||
? allMoves[this.sourceMove].name
|
? allMoves[this.sourceMove].name
|
||||||
: null;
|
: null;
|
||||||
@ -231,6 +231,44 @@ export class RechargingTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BattlerTag representing the "charge phase" of Beak Blast
|
||||||
|
* Pokemon with this tag will inflict BURN status on any attacker that makes contact.
|
||||||
|
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Beak_Blast_(move) | Beak Blast}
|
||||||
|
*/
|
||||||
|
export class BeakBlastChargingTag extends BattlerTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 1, Moves.BEAK_BLAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
// Play Beak Blast's charging animation
|
||||||
|
new MoveChargeAnim(ChargeAnim.BEAK_BLAST_CHARGING, this.sourceMove, pokemon).play(pokemon.scene);
|
||||||
|
|
||||||
|
// Queue Beak Blast's header message
|
||||||
|
pokemon.scene.queueMessage(i18next.t("moveTriggers:startedHeatingUpBeak", { pokemonName: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflicts `BURN` status on attackers that make contact, and causes this tag
|
||||||
|
* to be removed after the source makes a move (or the turn ends, whichever comes first)
|
||||||
|
* @param pokemon {@linkcode Pokemon} the owner of this tag
|
||||||
|
* @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle
|
||||||
|
* @returns `true` if invoked with the CUSTOM lapse type; `false` otherwise
|
||||||
|
*/
|
||||||
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
|
if (lapseType === BattlerTagLapseType.CUSTOM) {
|
||||||
|
const effectPhase = pokemon.scene.getCurrentPhase();
|
||||||
|
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
|
||||||
|
const attacker = effectPhase.getPokemon();
|
||||||
|
attacker.trySetStatus(StatusEffect.BURN, true, pokemon);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.lapse(pokemon, lapseType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TrappedTag extends BattlerTag {
|
export class TrappedTag extends BattlerTag {
|
||||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) {
|
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) {
|
||||||
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
||||||
@ -412,12 +450,12 @@ export class DestinyBondTag extends BattlerTag {
|
|||||||
if (lapseType !== BattlerTagLapseType.CUSTOM) {
|
if (lapseType !== BattlerTagLapseType.CUSTOM) {
|
||||||
return super.lapse(pokemon, lapseType);
|
return super.lapse(pokemon, lapseType);
|
||||||
}
|
}
|
||||||
const source = pokemon.scene.getPokemonById(this.sourceId);
|
const source = this.sourceId ? pokemon.scene.getPokemonById(this.sourceId) : null;
|
||||||
if (!source.isFainted()) {
|
if (!source?.isFainted()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.getAlly() === pokemon) {
|
if (source?.getAlly() === pokemon) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +481,19 @@ export class InfatuatedTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canAdd(pokemon: Pokemon): boolean {
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
return pokemon.isOppositeGender(pokemon.scene.getPokemonById(this.sourceId));
|
if (this.sourceId) {
|
||||||
|
const pkm = pokemon.scene.getPokemonById(this.sourceId);
|
||||||
|
|
||||||
|
if (pkm) {
|
||||||
|
return pokemon.isOppositeGender(pkm);
|
||||||
|
} else {
|
||||||
|
console.warn("canAdd: this.sourceId is not a valid pokemon id!", this.sourceId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("canAdd: this.sourceId is undefined");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
@ -452,7 +502,7 @@ export class InfatuatedTag extends BattlerTag {
|
|||||||
pokemon.scene.queueMessage(
|
pokemon.scene.queueMessage(
|
||||||
i18next.t("battle:battlerTagsInfatuatedOnAdd", {
|
i18next.t("battle:battlerTagsInfatuatedOnAdd", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined) // TODO: is that bang correct?
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -470,7 +520,7 @@ export class InfatuatedTag extends BattlerTag {
|
|||||||
pokemon.scene.queueMessage(
|
pokemon.scene.queueMessage(
|
||||||
i18next.t("battle:battlerTagsInfatuatedLapse", {
|
i18next.t("battle:battlerTagsInfatuatedLapse", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined) // TODO: is that bang correct?
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
|
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
|
||||||
@ -523,7 +573,7 @@ export class SeedTag extends BattlerTag {
|
|||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSeededOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSeededOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -669,11 +719,11 @@ export class EncoreTag extends BattlerTag {
|
|||||||
|
|
||||||
const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon);
|
const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon);
|
||||||
if (movePhase) {
|
if (movePhase) {
|
||||||
const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId);
|
const movesetMove = pokemon.getMoveset().find(m => m!.moveId === this.moveId); // TODO: is this bang correct?
|
||||||
if (movesetMove) {
|
if (movesetMove) {
|
||||||
const lastMove = pokemon.getLastXMoves(1)[0];
|
const lastMove = pokemon.getLastXMoves(1)[0];
|
||||||
pokemon.scene.tryReplacePhase((m => m instanceof MovePhase && m.pokemon === pokemon),
|
pokemon.scene.tryReplacePhase((m => m instanceof MovePhase && m.pokemon === pokemon),
|
||||||
new MovePhase(pokemon.scene, pokemon, lastMove.targets, movesetMove));
|
new MovePhase(pokemon.scene, pokemon, lastMove.targets!, movesetMove)); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -693,7 +743,7 @@ export class HelpingHandTag extends BattlerTag {
|
|||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
pokemon.scene.queueMessage(
|
pokemon.scene.queueMessage(
|
||||||
i18next.t("battle:battlerTagsHelpingHandOnAdd", {
|
i18next.t("battle:battlerTagsHelpingHandOnAdd", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon)
|
pokemonName: getPokemonNameWithAffix(pokemon)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -913,7 +963,7 @@ export class BindTag extends DamagingTrapTag {
|
|||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:battlerTagsBindOnTrap", {
|
return i18next.t("battle:battlerTagsBindOnTrap", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
|
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
moveName: this.getMoveName()
|
moveName: this.getMoveName()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -927,7 +977,7 @@ export class WrapTag extends DamagingTrapTag {
|
|||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:battlerTagsWrapOnTrap", {
|
return i18next.t("battle:battlerTagsWrapOnTrap", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -961,7 +1011,7 @@ export class ClampTag extends DamagingTrapTag {
|
|||||||
|
|
||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:battlerTagsClampOnTrap", {
|
return i18next.t("battle:battlerTagsClampOnTrap", {
|
||||||
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)),
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
pokemonName: getPokemonNameWithAffix(pokemon),
|
pokemonName: getPokemonNameWithAffix(pokemon),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1008,7 +1058,7 @@ export class ThunderCageTag extends DamagingTrapTag {
|
|||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:battlerTagsThunderCageOnTrap", {
|
return i18next.t("battle:battlerTagsThunderCageOnTrap", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1021,7 +1071,7 @@ export class InfestationTag extends DamagingTrapTag {
|
|||||||
getTrapMessage(pokemon: Pokemon): string {
|
getTrapMessage(pokemon: Pokemon): string {
|
||||||
return i18next.t("battle:battlerTagsInfestationOnTrap", {
|
return i18next.t("battle:battlerTagsInfestationOnTrap", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId))
|
sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1355,6 +1405,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
|
|||||||
return highestValue;
|
return highestValue;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
highestStat = highestStat!; // tell TS compiler it's defined!
|
||||||
this.stat = highestStat;
|
this.stat = highestStat;
|
||||||
|
|
||||||
switch (this.stat) {
|
switch (this.stat) {
|
||||||
@ -1540,7 +1591,7 @@ export class SaltCuredTag extends BattlerTag {
|
|||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSaltCuredOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSaltCuredOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -1587,7 +1638,7 @@ export class CursedTag extends BattlerTag {
|
|||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex();
|
this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
@ -1760,10 +1811,86 @@ export class StockpilingTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Battler tag for Gulp Missile used by Cramorant.
|
||||||
|
* @extends BattlerTag
|
||||||
|
*/
|
||||||
|
export class GulpMissileTag extends BattlerTag {
|
||||||
|
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
||||||
|
super(tagType, BattlerTagLapseType.CUSTOM, 0, sourceMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gulp Missile's initial form changes are triggered by using Surf and Dive.
|
||||||
|
* @param {Pokemon} pokemon The Pokemon with Gulp Missile ability.
|
||||||
|
* @returns Whether the BattlerTag can be added.
|
||||||
|
*/
|
||||||
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
|
const isSurfOrDive = [ Moves.SURF, Moves.DIVE ].includes(this.sourceMove);
|
||||||
|
const isNormalForm = pokemon.formIndex === 0 && !pokemon.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA) && !pokemon.getTag(BattlerTagType.GULP_MISSILE_PIKACHU);
|
||||||
|
const isCramorant = pokemon.species.speciesId === Species.CRAMORANT;
|
||||||
|
|
||||||
|
return isSurfOrDive && isNormalForm && isCramorant;
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd(pokemon: Pokemon): void {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(pokemon: Pokemon): void {
|
||||||
|
super.onRemove(pokemon);
|
||||||
|
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag that makes the target drop all of it type immunities
|
||||||
|
* and all accuracy checks ignore its evasiveness stat.
|
||||||
|
*
|
||||||
|
* Applied by moves: {@linkcode Moves.ODOR_SLEUTH | Odor Sleuth},
|
||||||
|
* {@linkcode Moves.MIRACLE_EYE | Miracle Eye} and {@linkcode Moves.FORESIGHT | Foresight}.
|
||||||
|
*
|
||||||
|
* @extends BattlerTag
|
||||||
|
* @see {@linkcode ignoreImmunity}
|
||||||
|
*/
|
||||||
|
export class ExposedTag extends BattlerTag {
|
||||||
|
private defenderType: Type;
|
||||||
|
private allowedTypes: Type[];
|
||||||
|
|
||||||
|
constructor(tagType: BattlerTagType, sourceMove: Moves, defenderType: Type, allowedTypes: Type[]) {
|
||||||
|
super(tagType, BattlerTagLapseType.CUSTOM, 1, sourceMove);
|
||||||
|
this.defenderType = defenderType;
|
||||||
|
this.allowedTypes = allowedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When given a battler tag or json representing one, load the data for it.
|
||||||
|
* @param {BattlerTag | any} source A battler tag
|
||||||
|
*/
|
||||||
|
loadTag(source: BattlerTag | any): void {
|
||||||
|
super.loadTag(source);
|
||||||
|
this.defenderType = source.defenderType as Type;
|
||||||
|
this.allowedTypes = source.allowedTypes as Type[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param types {@linkcode Type} of the defending Pokemon
|
||||||
|
* @param moveType {@linkcode Type} of the move targetting it
|
||||||
|
* @returns `true` if the move should be allowed to target the defender.
|
||||||
|
*/
|
||||||
|
ignoreImmunity(type: Type, moveType: Type): boolean {
|
||||||
|
return type === this.defenderType && this.allowedTypes.includes(moveType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
|
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case BattlerTagType.RECHARGING:
|
case BattlerTagType.RECHARGING:
|
||||||
return new RechargingTag(sourceMove);
|
return new RechargingTag(sourceMove);
|
||||||
|
case BattlerTagType.BEAK_BLAST_CHARGING:
|
||||||
|
return new BeakBlastChargingTag();
|
||||||
case BattlerTagType.FLINCHED:
|
case BattlerTagType.FLINCHED:
|
||||||
return new FlinchedTag(sourceMove);
|
return new FlinchedTag(sourceMove);
|
||||||
case BattlerTagType.INTERRUPTED:
|
case BattlerTagType.INTERRUPTED:
|
||||||
@ -1854,13 +1981,11 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
case BattlerTagType.ALWAYS_CRIT:
|
case BattlerTagType.ALWAYS_CRIT:
|
||||||
case BattlerTagType.IGNORE_ACCURACY:
|
case BattlerTagType.IGNORE_ACCURACY:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove);
|
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove);
|
||||||
case BattlerTagType.NO_CRIT:
|
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove);
|
|
||||||
case BattlerTagType.ALWAYS_GET_HIT:
|
case BattlerTagType.ALWAYS_GET_HIT:
|
||||||
case BattlerTagType.RECEIVE_DOUBLE_DAMAGE:
|
case BattlerTagType.RECEIVE_DOUBLE_DAMAGE:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.PRE_MOVE, 1, sourceMove);
|
return new BattlerTag(tagType, BattlerTagLapseType.PRE_MOVE, 1, sourceMove);
|
||||||
case BattlerTagType.BYPASS_SLEEP:
|
case BattlerTagType.BYPASS_SLEEP:
|
||||||
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
||||||
case BattlerTagType.IGNORE_FLYING:
|
case BattlerTagType.IGNORE_FLYING:
|
||||||
return new GroundedTag(tagType, BattlerTagLapseType.CUSTOM, sourceMove);
|
return new GroundedTag(tagType, BattlerTagLapseType.CUSTOM, sourceMove);
|
||||||
case BattlerTagType.ROOSTED:
|
case BattlerTagType.ROOSTED:
|
||||||
@ -1885,6 +2010,13 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
return new OctolockTag(sourceId);
|
return new OctolockTag(sourceId);
|
||||||
case BattlerTagType.DISABLED:
|
case BattlerTagType.DISABLED:
|
||||||
return new DisabledTag(sourceId);
|
return new DisabledTag(sourceId);
|
||||||
|
case BattlerTagType.IGNORE_GHOST:
|
||||||
|
return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]);
|
||||||
|
case BattlerTagType.IGNORE_DARK:
|
||||||
|
return new ExposedTag(tagType, sourceMove, Type.DARK, [Type.PSYCHIC]);
|
||||||
|
case BattlerTagType.GULP_MISSILE_ARROKUDA:
|
||||||
|
case BattlerTagType.GULP_MISSILE_PIKACHU:
|
||||||
|
return new GulpMissileTag(tagType, sourceMove);
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
@ -54,7 +54,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
|
|||||||
return (pokemon: Pokemon) => {
|
return (pokemon: Pokemon) => {
|
||||||
const threshold = new Utils.NumberHolder(0.25);
|
const threshold = new Utils.NumberHolder(0.25);
|
||||||
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold);
|
||||||
return !!pokemon.getMoveset().find(m => !m.getPpRatio());
|
return !!pokemon.getMoveset().find(m => !m?.getPpRatio());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,10 +120,10 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
|
|||||||
if (pokemon.battleData) {
|
if (pokemon.battleData) {
|
||||||
pokemon.battleData.berriesEaten.push(berryType);
|
pokemon.battleData.berriesEaten.push(berryType);
|
||||||
}
|
}
|
||||||
const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()) ? pokemon.getMoveset().find(m => !m.getPpRatio()) : pokemon.getMoveset().find(m => m.getPpRatio() < 1);
|
const ppRestoreMove = pokemon.getMoveset().find(m => !m?.getPpRatio()) ? pokemon.getMoveset().find(m => !m?.getPpRatio()) : pokemon.getMoveset().find(m => m!.getPpRatio() < 1); // TODO: is this bang correct?
|
||||||
if (ppRestoreMove !== undefined) {
|
if (ppRestoreMove !== undefined) {
|
||||||
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
|
ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0);
|
||||||
pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove.getName(), berryName: getBerryName(berryType) }));
|
pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7705,7 +7705,7 @@ export function initBiomes() {
|
|||||||
? pokemonEvolutions[speciesId]
|
? pokemonEvolutions[speciesId]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId))[3] as any[]).filter(b => b[0] !== Biome.END).length).length) {
|
if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId)!)[3] as any[]).filter(b => b[0] !== Biome.END).length).length) { // TODO: is the bang on the `find()` correct?
|
||||||
uncatchableSpecies.push(speciesId);
|
uncatchableSpecies.push(speciesId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,11 +273,9 @@ export abstract class Challenge {
|
|||||||
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
* @param valid {@link Utils.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.
|
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
||||||
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
||||||
* @param checkEvolutions {@link boolean} If true, check the pokemon's future evolutions
|
|
||||||
* @param checkForms {@link boolean} If true, check the pokemon's alternative forms
|
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns {@link boolean} Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean, checkForms?: boolean): boolean {
|
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,14 +403,13 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
super(Challenges.SINGLE_GENERATION, 9);
|
super(Challenges.SINGLE_GENERATION, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean): boolean {
|
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
|
||||||
const generations = [pokemon.generation];
|
const generations = [pokemon.generation];
|
||||||
const checkPokemonEvolutions = checkEvolutions ?? true as boolean;
|
|
||||||
if (soft) {
|
if (soft) {
|
||||||
const speciesToCheck = [pokemon.speciesId];
|
const speciesToCheck = [pokemon.speciesId];
|
||||||
while (speciesToCheck.length) {
|
while (speciesToCheck.length) {
|
||||||
const checking = speciesToCheck.pop();
|
const checking = speciesToCheck.pop();
|
||||||
if (pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) {
|
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
||||||
pokemonEvolutions[checking].forEach(e => {
|
pokemonEvolutions[checking].forEach(e => {
|
||||||
speciesToCheck.push(e.speciesId);
|
speciesToCheck.push(e.speciesId);
|
||||||
generations.push(getPokemonSpecies(e.speciesId).generation);
|
generations.push(getPokemonSpecies(e.speciesId).generation);
|
||||||
@ -430,7 +427,7 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
|
|
||||||
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean {
|
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean {
|
||||||
const baseGeneration = pokemon.species.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.species.speciesId).generation;
|
const baseGeneration = pokemon.species.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.species.speciesId).generation;
|
||||||
const fusionGeneration = pokemon.isFusion() ? pokemon.fusionSpecies.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.fusionSpecies.speciesId).generation : 0;
|
const fusionGeneration = pokemon.isFusion() ? pokemon.fusionSpecies?.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0; // TODO: is the bang on fusionSpecies correct?
|
||||||
if (pokemon.isPlayer() && (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))) {
|
if (pokemon.isPlayer() && (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))) {
|
||||||
valid.value = false;
|
valid.value = false;
|
||||||
return true;
|
return true;
|
||||||
@ -533,22 +530,20 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
super(Challenges.SINGLE_TYPE, 18);
|
super(Challenges.SINGLE_TYPE, 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean, checkForms?: boolean): boolean {
|
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean {
|
||||||
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
|
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
|
||||||
const types = [speciesForm.type1, speciesForm.type2];
|
const types = [speciesForm.type1, speciesForm.type2];
|
||||||
const checkPokemonEvolutions = checkEvolutions ?? true as boolean;
|
|
||||||
const checkPokemonForms = checkForms ?? true as boolean;
|
|
||||||
if (soft) {
|
if (soft) {
|
||||||
const speciesToCheck = [pokemon.speciesId];
|
const speciesToCheck = [pokemon.speciesId];
|
||||||
while (speciesToCheck.length) {
|
while (speciesToCheck.length) {
|
||||||
const checking = speciesToCheck.pop();
|
const checking = speciesToCheck.pop();
|
||||||
if (pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) {
|
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
||||||
pokemonEvolutions[checking].forEach(e => {
|
pokemonEvolutions[checking].forEach(e => {
|
||||||
speciesToCheck.push(e.speciesId);
|
speciesToCheck.push(e.speciesId);
|
||||||
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
|
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (pokemonFormChanges.hasOwnProperty(checking) && checkPokemonForms) {
|
if (checking && pokemonFormChanges.hasOwnProperty(checking)) {
|
||||||
pokemonFormChanges[checking].forEach(f1 => {
|
pokemonFormChanges[checking].forEach(f1 => {
|
||||||
getPokemonSpecies(checking).forms.forEach(f2 => {
|
getPokemonSpecies(checking).forms.forEach(f2 => {
|
||||||
if (f1.formKey === f2.formKey) {
|
if (f1.formKey === f2.formKey) {
|
||||||
@ -568,10 +563,11 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
|
|
||||||
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean {
|
applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean {
|
||||||
if (pokemon.isPlayer() && !pokemon.isOfType(this.value - 1, false, false, true)
|
if (pokemon.isPlayer() && !pokemon.isOfType(this.value - 1, false, false, true)
|
||||||
&& !SingleTypeChallenge.TYPE_OVERRIDES.some(o => o.type === (this.value - 1) && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies : pokemon.species).speciesId === o.species)) {
|
&& !SingleTypeChallenge.TYPE_OVERRIDES.some(o => o.type === (this.value - 1) && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species)) { // TODO: is the bang on fusionSpecies correct?
|
||||||
valid.value = false;
|
valid.value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -745,7 +741,7 @@ export class LowerStarterPointsChallenge extends Challenge {
|
|||||||
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
||||||
* @returns True if any challenge was successfully applied.
|
* @returns True if any challenge was successfully applied.
|
||||||
*/
|
*/
|
||||||
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean, checkEvolutions?: boolean, checkForms?: boolean): boolean;
|
export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean): boolean;
|
||||||
/**
|
/**
|
||||||
* Apply all challenges that modify available total starter points.
|
* Apply all challenges that modify available total starter points.
|
||||||
* @param gameMode {@link GameMode} The current gameMode
|
* @param gameMode {@link GameMode} The current gameMode
|
||||||
@ -853,7 +849,7 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||||||
if (c.value !== 0) {
|
if (c.value !== 0) {
|
||||||
switch (challengeType) {
|
switch (challengeType) {
|
||||||
case ChallengeType.STARTER_CHOICE:
|
case ChallengeType.STARTER_CHOICE:
|
||||||
ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3], args[4], args[5]);
|
ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3]);
|
||||||
break;
|
break;
|
||||||
case ChallengeType.STARTER_POINTS:
|
case ChallengeType.STARTER_POINTS:
|
||||||
ret ||= c.applyStarterPoints(args[0]);
|
ret ||= c.applyStarterPoints(args[0]);
|
||||||
|
@ -11,15 +11,15 @@ export interface DailyRunConfig {
|
|||||||
starters: Starter;
|
starters: Starter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchDailyRunSeed(): Promise<string> {
|
export function fetchDailyRunSeed(): Promise<string | null> {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string | null>((resolve, reject) => {
|
||||||
Utils.apiFetch("daily/seed").then(response => {
|
Utils.apiFetch("daily/seed").then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return response.text();
|
return response.text();
|
||||||
}).then(seed => resolve(seed))
|
}).then(seed => resolve(seed!)) // TODO: is this bang correct?
|
||||||
.catch(err => reject(err));
|
.catch(err => reject(err));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -452,144 +452,304 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
|
|||||||
[TrainerType.ROCKET_GRUNT]: [
|
[TrainerType.ROCKET_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:rocket_grunt.encounter.1"
|
"dialogue:rocket_grunt.encounter.1",
|
||||||
|
"dialogue:rocket_grunt.encounter.2",
|
||||||
|
"dialogue:rocket_grunt.encounter.3",
|
||||||
|
"dialogue:rocket_grunt.encounter.4",
|
||||||
|
"dialogue:rocket_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:rocket_grunt.victory.1"
|
"dialogue:rocket_grunt.victory.1",
|
||||||
|
"dialogue:rocket_grunt.victory.2",
|
||||||
|
"dialogue:rocket_grunt.victory.3",
|
||||||
|
"dialogue:rocket_grunt.victory.4",
|
||||||
|
"dialogue:rocket_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.ROCKET_ADMIN]: [
|
[TrainerType.ARCHER]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:rocket_admin.encounter.1",
|
"dialogue:archer.encounter.1",
|
||||||
"dialogue:rocket_admin.encounter.2",
|
"dialogue:archer.encounter.2",
|
||||||
"dialogue:rocket_admin.encounter.3",
|
"dialogue:archer.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:rocket_admin.victory.1",
|
"dialogue:archer.victory.1",
|
||||||
"dialogue:rocket_admin.victory.2",
|
"dialogue:archer.victory.2",
|
||||||
"dialogue:rocket_admin.victory.3",
|
"dialogue:archer.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.ARIANA]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:ariana.encounter.1",
|
||||||
|
"dialogue:ariana.encounter.2",
|
||||||
|
"dialogue:ariana.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:ariana.victory.1",
|
||||||
|
"dialogue:ariana.victory.2",
|
||||||
|
"dialogue:ariana.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.PROTON]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:proton.encounter.1",
|
||||||
|
"dialogue:proton.encounter.2",
|
||||||
|
"dialogue:proton.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:proton.victory.1",
|
||||||
|
"dialogue:proton.victory.2",
|
||||||
|
"dialogue:proton.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.PETREL]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:petrel.encounter.1",
|
||||||
|
"dialogue:petrel.encounter.2",
|
||||||
|
"dialogue:petrel.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:petrel.victory.1",
|
||||||
|
"dialogue:petrel.victory.2",
|
||||||
|
"dialogue:petrel.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.MAGMA_GRUNT]: [
|
[TrainerType.MAGMA_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:magma_grunt.encounter.1"
|
"dialogue:magma_grunt.encounter.1",
|
||||||
|
"dialogue:magma_grunt.encounter.2",
|
||||||
|
"dialogue:magma_grunt.encounter.3",
|
||||||
|
"dialogue:magma_grunt.encounter.4",
|
||||||
|
"dialogue:magma_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:magma_grunt.victory.1"
|
"dialogue:magma_grunt.victory.1",
|
||||||
|
"dialogue:magma_grunt.victory.2",
|
||||||
|
"dialogue:magma_grunt.victory.3",
|
||||||
|
"dialogue:magma_grunt.victory.4",
|
||||||
|
"dialogue:magma_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.MAGMA_ADMIN]: [
|
[TrainerType.TABITHA]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:magma_admin.encounter.1",
|
"dialogue:tabitha.encounter.1",
|
||||||
"dialogue:magma_admin.encounter.2",
|
"dialogue:tabitha.encounter.2",
|
||||||
"dialogue:magma_admin.encounter.3",
|
"dialogue:tabitha.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:magma_admin.victory.1",
|
"dialogue:tabitha.victory.1",
|
||||||
"dialogue:magma_admin.victory.2",
|
"dialogue:tabitha.victory.2",
|
||||||
"dialogue:magma_admin.victory.3",
|
"dialogue:tabitha.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.COURTNEY]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:courtney.encounter.1",
|
||||||
|
"dialogue:courtney.encounter.2",
|
||||||
|
"dialogue:courtney.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:courtney.victory.1",
|
||||||
|
"dialogue:courtney.victory.2",
|
||||||
|
"dialogue:courtney.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.AQUA_GRUNT]: [
|
[TrainerType.AQUA_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:aqua_grunt.encounter.1"
|
"dialogue:aqua_grunt.encounter.1",
|
||||||
|
"dialogue:aqua_grunt.encounter.2",
|
||||||
|
"dialogue:aqua_grunt.encounter.3",
|
||||||
|
"dialogue:aqua_grunt.encounter.4",
|
||||||
|
"dialogue:aqua_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:aqua_grunt.victory.1"
|
"dialogue:aqua_grunt.victory.1",
|
||||||
|
"dialogue:aqua_grunt.victory.2",
|
||||||
|
"dialogue:aqua_grunt.victory.3",
|
||||||
|
"dialogue:aqua_grunt.victory.4",
|
||||||
|
"dialogue:aqua_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.AQUA_ADMIN]: [
|
[TrainerType.MATT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:aqua_admin.encounter.1",
|
"dialogue:matt.encounter.1",
|
||||||
"dialogue:aqua_admin.encounter.2",
|
"dialogue:matt.encounter.2",
|
||||||
"dialogue:aqua_admin.encounter.3",
|
"dialogue:matt.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:aqua_admin.victory.1",
|
"dialogue:matt.victory.1",
|
||||||
"dialogue:aqua_admin.victory.2",
|
"dialogue:matt.victory.2",
|
||||||
"dialogue:aqua_admin.victory.3",
|
"dialogue:matt.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.SHELLY]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:shelly.encounter.1",
|
||||||
|
"dialogue:shelly.encounter.2",
|
||||||
|
"dialogue:shelly.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:shelly.victory.1",
|
||||||
|
"dialogue:shelly.victory.2",
|
||||||
|
"dialogue:shelly.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.GALACTIC_GRUNT]: [
|
[TrainerType.GALACTIC_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:galactic_grunt.encounter.1"
|
"dialogue:galactic_grunt.encounter.1",
|
||||||
|
"dialogue:galactic_grunt.encounter.2",
|
||||||
|
"dialogue:galactic_grunt.encounter.3",
|
||||||
|
"dialogue:galactic_grunt.encounter.4",
|
||||||
|
"dialogue:galactic_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:galactic_grunt.victory.1"
|
"dialogue:galactic_grunt.victory.1",
|
||||||
|
"dialogue:galactic_grunt.victory.2",
|
||||||
|
"dialogue:galactic_grunt.victory.3",
|
||||||
|
"dialogue:galactic_grunt.victory.4",
|
||||||
|
"dialogue:galactic_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.GALACTIC_ADMIN]: [
|
[TrainerType.JUPITER]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:galactic_admin.encounter.1",
|
"dialogue:jupiter.encounter.1",
|
||||||
"dialogue:galactic_admin.encounter.2",
|
"dialogue:jupiter.encounter.2",
|
||||||
"dialogue:galactic_admin.encounter.3",
|
"dialogue:jupiter.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:galactic_admin.victory.1",
|
"dialogue:jupiter.victory.1",
|
||||||
"dialogue:galactic_admin.victory.2",
|
"dialogue:jupiter.victory.2",
|
||||||
"dialogue:galactic_admin.victory.3",
|
"dialogue:jupiter.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.MARS]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:mars.encounter.1",
|
||||||
|
"dialogue:mars.encounter.2",
|
||||||
|
"dialogue:mars.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:mars.victory.1",
|
||||||
|
"dialogue:mars.victory.2",
|
||||||
|
"dialogue:mars.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.SATURN]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:saturn.encounter.1",
|
||||||
|
"dialogue:saturn.encounter.2",
|
||||||
|
"dialogue:saturn.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:saturn.victory.1",
|
||||||
|
"dialogue:saturn.victory.2",
|
||||||
|
"dialogue:saturn.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.PLASMA_GRUNT]: [
|
[TrainerType.PLASMA_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:plasma_grunt.encounter.1"
|
"dialogue:plasma_grunt.encounter.1",
|
||||||
|
"dialogue:plasma_grunt.encounter.2",
|
||||||
|
"dialogue:plasma_grunt.encounter.3",
|
||||||
|
"dialogue:plasma_grunt.encounter.4",
|
||||||
|
"dialogue:plasma_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:plasma_grunt.victory.1"
|
"dialogue:plasma_grunt.victory.1",
|
||||||
|
"dialogue:plasma_grunt.victory.2",
|
||||||
|
"dialogue:plasma_grunt.victory.3",
|
||||||
|
"dialogue:plasma_grunt.victory.4",
|
||||||
|
"dialogue:plasma_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.PLASMA_SAGE]: [
|
[TrainerType.ZINZOLIN]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:plasma_sage.encounter.1",
|
"dialogue:zinzolin.encounter.1",
|
||||||
"dialogue:plasma_sage.encounter.2",
|
"dialogue:zinzolin.encounter.2",
|
||||||
"dialogue:plasma_sage.encounter.3",
|
"dialogue:zinzolin.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:plasma_sage.victory.1",
|
"dialogue:zinzolin.victory.1",
|
||||||
"dialogue:plasma_sage.victory.2",
|
"dialogue:zinzolin.victory.2",
|
||||||
"dialogue:plasma_sage.victory.3",
|
"dialogue:zinzolin.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.FLARE_GRUNT]: [
|
[TrainerType.FLARE_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:flare_grunt.encounter.1"
|
"dialogue:flare_grunt.encounter.1",
|
||||||
|
"dialogue:flare_grunt.encounter.2",
|
||||||
|
"dialogue:flare_grunt.encounter.3",
|
||||||
|
"dialogue:flare_grunt.encounter.4",
|
||||||
|
"dialogue:flare_grunt.encounter.5",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:flare_grunt.victory.1"
|
"dialogue:flare_grunt.victory.1",
|
||||||
|
"dialogue:flare_grunt.victory.2",
|
||||||
|
"dialogue:flare_grunt.victory.3",
|
||||||
|
"dialogue:flare_grunt.victory.4",
|
||||||
|
"dialogue:flare_grunt.victory.5",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[TrainerType.FLARE_ADMIN]: [
|
[TrainerType.BRYONY]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
"dialogue:flare_admin.encounter.1",
|
"dialogue:bryony.encounter.1",
|
||||||
"dialogue:flare_admin.encounter.2",
|
"dialogue:bryony.encounter.2",
|
||||||
"dialogue:flare_admin.encounter.3",
|
"dialogue:bryony.encounter.3",
|
||||||
],
|
],
|
||||||
victory: [
|
victory: [
|
||||||
"dialogue:flare_admin.victory.1",
|
"dialogue:bryony.victory.1",
|
||||||
"dialogue:flare_admin.victory.2",
|
"dialogue:bryony.victory.2",
|
||||||
"dialogue:flare_admin.victory.3",
|
"dialogue:bryony.victory.3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[TrainerType.XEROSIC]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:xerosic.encounter.1",
|
||||||
|
"dialogue:xerosic.encounter.2",
|
||||||
|
"dialogue:xerosic.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:xerosic.victory.1",
|
||||||
|
"dialogue:xerosic.victory.2",
|
||||||
|
"dialogue:xerosic.victory.3",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -140,30 +140,30 @@ export class Egg {
|
|||||||
constructor(eggOptions?: IEggOptions) {
|
constructor(eggOptions?: IEggOptions) {
|
||||||
//if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.")
|
//if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.")
|
||||||
|
|
||||||
this._sourceType = eggOptions.sourceType ?? undefined;
|
this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct?
|
||||||
// Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced
|
// Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced
|
||||||
this._tier = eggOptions.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier());
|
this._tier = eggOptions?.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier());
|
||||||
// If egg was pulled, check if egg pity needs to override the egg tier
|
// If egg was pulled, check if egg pity needs to override the egg tier
|
||||||
if (eggOptions.pulled) {
|
if (eggOptions?.pulled) {
|
||||||
// Needs this._tier and this._sourceType to work
|
// Needs this._tier and this._sourceType to work
|
||||||
this.checkForPityTierOverrides(eggOptions.scene);
|
this.checkForPityTierOverrides(eggOptions.scene!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
this._id = eggOptions.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
||||||
|
|
||||||
this._sourceType = eggOptions.sourceType ?? undefined;
|
this._sourceType = eggOptions?.sourceType ?? undefined;
|
||||||
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
this._timestamp = eggOptions.timestamp ?? new Date().getTime();
|
this._timestamp = eggOptions?.timestamp ?? new Date().getTime();
|
||||||
|
|
||||||
// First roll shiny and variant so we can filter if species with an variant exist
|
// First roll shiny and variant so we can filter if species with an variant exist
|
||||||
this._isShiny = eggOptions.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
|
this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
|
||||||
this._variantTier = eggOptions.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant());
|
this._variantTier = eggOptions?.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant());
|
||||||
this._species = eggOptions.species ?? this.rollSpecies(eggOptions.scene);
|
this._species = eggOptions?.species ?? this.rollSpecies(eggOptions!.scene!)!; // TODO: Are those bangs correct?
|
||||||
|
|
||||||
this._overrideHiddenAbility = eggOptions.overrideHiddenAbility ?? false;
|
this._overrideHiddenAbility = eggOptions?.overrideHiddenAbility ?? false;
|
||||||
|
|
||||||
// Override egg tier and hatchwaves if species was given
|
// Override egg tier and hatchwaves if species was given
|
||||||
if (eggOptions.species) {
|
if (eggOptions?.species) {
|
||||||
this._tier = this.getEggTierFromSpeciesStarterValue();
|
this._tier = this.getEggTierFromSpeciesStarterValue();
|
||||||
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
}
|
}
|
||||||
@ -174,10 +174,10 @@ export class Egg {
|
|||||||
this._variantTier = VariantTier.COMMON;
|
this._variantTier = VariantTier.COMMON;
|
||||||
}
|
}
|
||||||
// Needs this._tier so it needs to be generated afer the tier override if bought from same species
|
// Needs this._tier so it needs to be generated afer the tier override if bought from same species
|
||||||
this._eggMoveIndex = eggOptions.eggMoveIndex ?? this.rollEggMoveIndex();
|
this._eggMoveIndex = eggOptions?.eggMoveIndex ?? this.rollEggMoveIndex();
|
||||||
if (eggOptions.pulled) {
|
if (eggOptions?.pulled) {
|
||||||
this.increasePullStatistic(eggOptions.scene);
|
this.increasePullStatistic(eggOptions.scene!); // TODO: is this bang correct?
|
||||||
this.addEggToGameData(eggOptions.scene);
|
this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,14 +202,18 @@ export class Egg {
|
|||||||
// Legacy egg wants to hatch. Generate missing properties
|
// Legacy egg wants to hatch. Generate missing properties
|
||||||
if (!this._species) {
|
if (!this._species) {
|
||||||
this._isShiny = this.rollShiny();
|
this._isShiny = this.rollShiny();
|
||||||
this._species = this.rollSpecies(scene);
|
this._species = this.rollSpecies(scene!)!; // TODO: are these bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
const pokemonSpecies = getPokemonSpecies(this._species);
|
let pokemonSpecies = getPokemonSpecies(this._species);
|
||||||
|
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
||||||
|
if (this._species === Species.PHIONE) {
|
||||||
|
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the hidden ability if a hidden ability exists and the override is set
|
// Sets the hidden ability if a hidden ability exists and the override is set
|
||||||
// or if the same species egg hits the chance
|
// or if the same species egg hits the chance
|
||||||
let abilityIndex = undefined;
|
let abilityIndex: number | undefined = undefined;
|
||||||
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility
|
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility
|
||||||
|| (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE)))) {
|
|| (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE)))) {
|
||||||
abilityIndex = 2;
|
abilityIndex = 2;
|
||||||
@ -273,6 +277,9 @@ export class Egg {
|
|||||||
return i18next.t("egg:gachaTypeShiny");
|
return i18next.t("egg:gachaTypeShiny");
|
||||||
case EggSourceType.GACHA_MOVE:
|
case EggSourceType.GACHA_MOVE:
|
||||||
return i18next.t("egg:gachaTypeMove");
|
return i18next.t("egg:gachaTypeMove");
|
||||||
|
default:
|
||||||
|
console.warn("getEggTypeDescriptor case not defined. Returning default empty string");
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,9 +329,9 @@ export class Egg {
|
|||||||
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
|
return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
private rollSpecies(scene: BattleScene): Species {
|
private rollSpecies(scene: BattleScene): Species | null {
|
||||||
if (!scene) {
|
if (!scene) {
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione
|
* Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione
|
||||||
@ -396,7 +403,7 @@ export class Egg {
|
|||||||
* and being the same each time
|
* and being the same each time
|
||||||
*/
|
*/
|
||||||
let totalWeight = 0;
|
let totalWeight = 0;
|
||||||
const speciesWeights = [];
|
const speciesWeights : number[] = [];
|
||||||
for (const speciesId of speciesPool) {
|
for (const speciesId of speciesPool) {
|
||||||
let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
|
let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100);
|
||||||
const species = getPokemonSpecies(speciesId);
|
const species = getPokemonSpecies(speciesId);
|
||||||
@ -416,6 +423,7 @@ export class Egg {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
species = species!; // tell TS compiled it's defined now!
|
||||||
|
|
||||||
if (!!scene.gameData.dexData[species].caughtAttr || scene.gameData.eggs.some(e => e.species === species)) {
|
if (!!scene.gameData.dexData[species].caughtAttr || scene.gameData.eggs.some(e => e.species === species)) {
|
||||||
scene.gameData.unlockPity[this.tier] = Math.min(scene.gameData.unlockPity[this.tier] + 1, 10);
|
scene.gameData.unlockPity[this.tier] = Math.min(scene.gameData.unlockPity[this.tier] + 1, 10);
|
||||||
@ -513,6 +521,8 @@ export class Egg {
|
|||||||
if (speciesStartValue >= 8) {
|
if (speciesStartValue >= 8) {
|
||||||
return EggTier.MASTER;
|
return EggTier.MASTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EggTier.COMMON;
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
@ -537,6 +547,7 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta
|
|||||||
scene.executeWithSeedOffset(() => {
|
scene.executeWithSeedOffset(() => {
|
||||||
ret = Phaser.Math.RND.shuffle(legendarySpecies)[index];
|
ret = Phaser.Math.RND.shuffle(legendarySpecies)[index];
|
||||||
}, offset, EGG_SEED.toString());
|
}, offset, EGG_SEED.toString());
|
||||||
|
ret = ret!; // tell TS compiler it's
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
529
src/data/move.ts
@ -15,8 +15,8 @@ export function getNatureName(nature: Nature, includeStatEffects: boolean = fals
|
|||||||
}
|
}
|
||||||
if (includeStatEffects) {
|
if (includeStatEffects) {
|
||||||
const stats = Utils.getEnumValues(Stat).slice(1);
|
const stats = Utils.getEnumValues(Stat).slice(1);
|
||||||
let increasedStat: Stat = null;
|
let increasedStat: Stat | null = null;
|
||||||
let decreasedStat: Stat = null;
|
let decreasedStat: Stat | null = null;
|
||||||
for (const stat of stats) {
|
for (const stat of stats) {
|
||||||
const multiplier = getNatureStatMultiplier(nature, stat);
|
const multiplier = getNatureStatMultiplier(nature, stat);
|
||||||
if (multiplier > 1) {
|
if (multiplier > 1) {
|
||||||
|
@ -59,26 +59,26 @@ export type EvolutionConditionEnforceFunc = (p: Pokemon) => void;
|
|||||||
|
|
||||||
export class SpeciesFormEvolution {
|
export class SpeciesFormEvolution {
|
||||||
public speciesId: Species;
|
public speciesId: Species;
|
||||||
public preFormKey: string;
|
public preFormKey: string | null;
|
||||||
public evoFormKey: string;
|
public evoFormKey: string | null;
|
||||||
public level: integer;
|
public level: integer;
|
||||||
public item: EvolutionItem;
|
public item: EvolutionItem | null;
|
||||||
public condition: SpeciesEvolutionCondition;
|
public condition: SpeciesEvolutionCondition | null;
|
||||||
public wildDelay: SpeciesWildEvolutionDelay;
|
public wildDelay: SpeciesWildEvolutionDelay;
|
||||||
|
|
||||||
constructor(speciesId: Species, preFormKey: string, evoFormKey: string, level: integer, item: EvolutionItem, condition: SpeciesEvolutionCondition, wildDelay?: SpeciesWildEvolutionDelay) {
|
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
|
||||||
this.speciesId = speciesId;
|
this.speciesId = speciesId;
|
||||||
this.preFormKey = preFormKey;
|
this.preFormKey = preFormKey;
|
||||||
this.evoFormKey = evoFormKey;
|
this.evoFormKey = evoFormKey;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.item = item || EvolutionItem.NONE;
|
this.item = item || EvolutionItem.NONE;
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.wildDelay = wildDelay || SpeciesWildEvolutionDelay.NONE;
|
this.wildDelay = wildDelay ?? SpeciesWildEvolutionDelay.NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SpeciesEvolution extends SpeciesFormEvolution {
|
export class SpeciesEvolution extends SpeciesFormEvolution {
|
||||||
constructor(speciesId: Species, level: integer, item: EvolutionItem, condition: SpeciesEvolutionCondition, wildDelay?: SpeciesWildEvolutionDelay) {
|
constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
|
||||||
super(speciesId, null, null, level, item, condition, wildDelay);
|
super(speciesId, null, null, level, item, condition, wildDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ export class FusionSpeciesFormEvolution extends SpeciesFormEvolution {
|
|||||||
|
|
||||||
export class SpeciesEvolutionCondition {
|
export class SpeciesEvolutionCondition {
|
||||||
public predicate: EvolutionConditionPredicate;
|
public predicate: EvolutionConditionPredicate;
|
||||||
public enforceFunc: EvolutionConditionEnforceFunc;
|
public enforceFunc: EvolutionConditionEnforceFunc | undefined;
|
||||||
|
|
||||||
constructor(predicate: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
|
constructor(predicate: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) {
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
@ -400,8 +400,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.LINOONE, 20, null, null)
|
new SpeciesEvolution(Species.LINOONE, 20, null, null)
|
||||||
],
|
],
|
||||||
[Species.WURMPLE]: [
|
[Species.WURMPLE]: [
|
||||||
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
|
new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)),
|
||||||
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
|
new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||||
],
|
],
|
||||||
[Species.SILCOON]: [
|
[Species.SILCOON]: [
|
||||||
new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null)
|
new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null)
|
||||||
@ -945,7 +945,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.SHIINOTIC, 24, null, null)
|
new SpeciesEvolution(Species.SHIINOTIC, 24, null, null)
|
||||||
],
|
],
|
||||||
[Species.SALANDIT]: [
|
[Species.SALANDIT]: [
|
||||||
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), null)
|
new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE))
|
||||||
],
|
],
|
||||||
[Species.STUFFUL]: [
|
[Species.STUFFUL]: [
|
||||||
new SpeciesEvolution(Species.BEWEAR, 27, null, null)
|
new SpeciesEvolution(Species.BEWEAR, 27, null, null)
|
||||||
@ -969,8 +969,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.COSMOEM, 43, null, null)
|
new SpeciesEvolution(Species.COSMOEM, 43, null, null)
|
||||||
],
|
],
|
||||||
[Species.COSMOEM]: [
|
[Species.COSMOEM]: [
|
||||||
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
|
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)),
|
||||||
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
|
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT))
|
||||||
],
|
],
|
||||||
[Species.MELTAN]: [
|
[Species.MELTAN]: [
|
||||||
new SpeciesEvolution(Species.MELMETAL, 48, null, null)
|
new SpeciesEvolution(Species.MELMETAL, 48, null, null)
|
||||||
@ -1264,17 +1264,17 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.EXEGGUTOR, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.EXEGGUTOR, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.TANGELA]: [
|
[Species.TANGELA]: [
|
||||||
new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.LICKITUNG]: [
|
[Species.LICKITUNG]: [
|
||||||
new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.STARYU]: [
|
[Species.STARYU]: [
|
||||||
new SpeciesEvolution(Species.STARMIE, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.STARMIE, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.EEVEE]: [
|
[Species.EEVEE]: [
|
||||||
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
||||||
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG),
|
||||||
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
||||||
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG),
|
||||||
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG),
|
||||||
@ -1294,13 +1294,13 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.TOGEKISS, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.TOGEKISS, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.AIPOM]: [
|
[Species.AIPOM]: [
|
||||||
new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.SUNKERN]: [
|
[Species.SUNKERN]: [
|
||||||
new SpeciesEvolution(Species.SUNFLORA, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.SUNFLORA, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.YANMA]: [
|
[Species.YANMA]: [
|
||||||
new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.MURKROW]: [
|
[Species.MURKROW]: [
|
||||||
new SpeciesEvolution(Species.HONCHKROW, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.HONCHKROW, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
@ -1309,17 +1309,17 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.MISMAGIUS, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.MISMAGIUS, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.GIRAFARIG]: [
|
[Species.GIRAFARIG]: [
|
||||||
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.DUNSPARCE]: [
|
[Species.DUNSPARCE]: [
|
||||||
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => {
|
new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => {
|
||||||
let ret = false;
|
let ret = false;
|
||||||
if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) {
|
if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) {
|
||||||
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}), SpeciesWildEvolutionDelay.LONG),
|
}), SpeciesWildEvolutionDelay.LONG),
|
||||||
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.GLIGAR]: [
|
[Species.GLIGAR]: [
|
||||||
new SpeciesEvolution(Species.GLISCOR, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor fang at night*/), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.GLISCOR, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor fang at night*/), SpeciesWildEvolutionDelay.LONG)
|
||||||
@ -1331,10 +1331,10 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.URSALUNA, 1, EvolutionItem.PEAT_BLOCK, null, SpeciesWildEvolutionDelay.VERY_LONG) //Ursaring does not evolve into Bloodmoon Ursaluna
|
new SpeciesEvolution(Species.URSALUNA, 1, EvolutionItem.PEAT_BLOCK, null, SpeciesWildEvolutionDelay.VERY_LONG) //Ursaring does not evolve into Bloodmoon Ursaluna
|
||||||
],
|
],
|
||||||
[Species.PILOSWINE]: [
|
[Species.PILOSWINE]: [
|
||||||
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.STANTLER]: [
|
[Species.STANTLER]: [
|
||||||
new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.LOMBRE]: [
|
[Species.LOMBRE]: [
|
||||||
new SpeciesEvolution(Species.LUDICOLO, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.LUDICOLO, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
@ -1352,11 +1352,11 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.ROSERADE, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.ROSERADE, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.BONSLY]: [
|
[Species.BONSLY]: [
|
||||||
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
||||||
],
|
],
|
||||||
[Species.MIME_JR]: [
|
[Species.MIME_JR]: [
|
||||||
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.biomeType === Biome.ICE_CAVE || p.scene.arena.biomeType === Biome.SNOWY_FOREST)), SpeciesWildEvolutionDelay.MEDIUM),
|
new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.biomeType === Biome.ICE_CAVE || p.scene.arena.biomeType === Biome.SNOWY_FOREST)), SpeciesWildEvolutionDelay.MEDIUM),
|
||||||
new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
||||||
],
|
],
|
||||||
[Species.PANSAGE]: [
|
[Species.PANSAGE]: [
|
||||||
new SpeciesEvolution(Species.SIMISAGE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.SIMISAGE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
@ -1406,15 +1406,15 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.ROCKRUFF]: [
|
[Species.ROCKRUFF]: [
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0)), null),
|
new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))),
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1), null),
|
new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)),
|
||||||
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)), null)
|
new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)))
|
||||||
],
|
],
|
||||||
[Species.STEENEE]: [
|
[Species.STEENEE]: [
|
||||||
new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.POIPOLE]: [
|
[Species.POIPOLE]: [
|
||||||
new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.ALOLA_SANDSHREW]: [
|
[Species.ALOLA_SANDSHREW]: [
|
||||||
new SpeciesEvolution(Species.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
@ -1428,7 +1428,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.APPLETUN, 1, EvolutionItem.SWEET_APPLE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.APPLETUN, 1, EvolutionItem.SWEET_APPLE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.CLOBBOPUS]: [
|
[Species.CLOBBOPUS]: [
|
||||||
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.TAUNT).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TAUNT).length > 0), SpeciesWildEvolutionDelay.MEDIUM)
|
||||||
],
|
],
|
||||||
[Species.SINISTEA]: [
|
[Species.SINISTEA]: [
|
||||||
new SpeciesFormEvolution(Species.POLTEAGEIST, "phony", "phony", 1, EvolutionItem.CRACKED_POT, null, SpeciesWildEvolutionDelay.LONG),
|
new SpeciesFormEvolution(Species.POLTEAGEIST, "phony", "phony", 1, EvolutionItem.CRACKED_POT, null, SpeciesWildEvolutionDelay.LONG),
|
||||||
@ -1462,7 +1462,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.HISUI_ELECTRODE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.HISUI_ELECTRODE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.HISUI_QWILFISH]: [
|
[Species.HISUI_QWILFISH]: [
|
||||||
new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.HISUI_SNEASEL]: [
|
[Species.HISUI_SNEASEL]: [
|
||||||
new SpeciesEvolution(Species.SNEASLER, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY /* Razor claw at day*/), SpeciesWildEvolutionDelay.LONG)
|
new SpeciesEvolution(Species.SNEASLER, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY /* Razor claw at day*/), SpeciesWildEvolutionDelay.LONG)
|
||||||
@ -1485,7 +1485,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesFormEvolution(Species.SINISTCHA, "artisan", "masterpiece", 1, EvolutionItem.MASTERPIECE_TEACUP, null, SpeciesWildEvolutionDelay.LONG)
|
new SpeciesFormEvolution(Species.SINISTCHA, "artisan", "masterpiece", 1, EvolutionItem.MASTERPIECE_TEACUP, null, SpeciesWildEvolutionDelay.LONG)
|
||||||
],
|
],
|
||||||
[Species.DIPPLIN]: [
|
[Species.DIPPLIN]: [
|
||||||
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.KADABRA]: [
|
[Species.KADABRA]: [
|
||||||
new SpeciesEvolution(Species.ALAKAZAM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.ALAKAZAM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
@ -1501,7 +1501,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
],
|
],
|
||||||
[Species.ONIX]: [
|
[Species.ONIX]: [
|
||||||
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
||||||
p => p.moveset.filter(m => m.getMove().type === Type.STEEL).length > 0),
|
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
|
||||||
SpeciesWildEvolutionDelay.VERY_LONG)
|
SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.RHYDON]: [
|
[Species.RHYDON]: [
|
||||||
@ -1512,7 +1512,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
],
|
],
|
||||||
[Species.SCYTHER]: [
|
[Species.SCYTHER]: [
|
||||||
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(
|
||||||
p => p.moveset.filter(m => m.getMove().type === Type.STEEL).length > 0),
|
p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0),
|
||||||
SpeciesWildEvolutionDelay.VERY_LONG),
|
SpeciesWildEvolutionDelay.VERY_LONG),
|
||||||
new SpeciesEvolution(Species.KLEAVOR, 1, EvolutionItem.BLACK_AUGURITE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.KLEAVOR, 1, EvolutionItem.BLACK_AUGURITE, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
@ -1566,7 +1566,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
|||||||
new SpeciesEvolution(Species.ALOLA_GOLEM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.ALOLA_GOLEM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.PRIMEAPE]: [
|
[Species.PRIMEAPE]: [
|
||||||
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
],
|
],
|
||||||
[Species.GOLBAT]: [
|
[Species.GOLBAT]: [
|
||||||
new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesFriendshipEvolutionCondition(110), SpeciesWildEvolutionDelay.VERY_LONG)
|
new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesFriendshipEvolutionCondition(110), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||||
|
@ -181,7 +181,7 @@ export class SpeciesFormChange {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger {
|
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | null {
|
||||||
if (!this.trigger.hasTriggerType(triggerType)) {
|
if (!this.trigger.hasTriggerType(triggerType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ export class SpeciesFormChange {
|
|||||||
const trigger = this.trigger;
|
const trigger = this.trigger;
|
||||||
|
|
||||||
if (trigger instanceof SpeciesFormChangeCompoundTrigger) {
|
if (trigger instanceof SpeciesFormChangeCompoundTrigger) {
|
||||||
return trigger.triggers.find(t => t.hasTriggerType(triggerType));
|
return trigger.triggers.find(t => t.hasTriggerType(triggerType))!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
return trigger;
|
return trigger;
|
||||||
@ -198,11 +198,11 @@ export class SpeciesFormChange {
|
|||||||
|
|
||||||
export class SpeciesFormChangeCondition {
|
export class SpeciesFormChangeCondition {
|
||||||
public predicate: SpeciesFormChangeConditionPredicate;
|
public predicate: SpeciesFormChangeConditionPredicate;
|
||||||
public enforceFunc: SpeciesFormChangeConditionEnforceFunc;
|
public enforceFunc: SpeciesFormChangeConditionEnforceFunc | null;
|
||||||
|
|
||||||
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
|
constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) {
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
this.enforceFunc = enforceFunc;
|
this.enforceFunc = enforceFunc!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigge
|
|||||||
}
|
}
|
||||||
|
|
||||||
canChange(pokemon: Pokemon): boolean {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
return (!!pokemon.moveset.filter(m => m.moveId === this.move).length) === this.known;
|
return (!!pokemon.moveset.filter(m => m?.moveId === this.move).length) === this.known;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +332,7 @@ export abstract class SpeciesFormChangeMoveTrigger extends SpeciesFormChangeTrig
|
|||||||
export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger {
|
export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger {
|
||||||
canChange(pokemon: Pokemon): boolean {
|
canChange(pokemon: Pokemon): boolean {
|
||||||
const command = pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
const command = pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
|
||||||
return command?.move && this.movePredicate(command.move.move) === this.used;
|
return !!command?.move && this.movePredicate(command.move.move) === this.used;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,6 +828,12 @@ export const pokemonFormChanges: PokemonFormChanges = {
|
|||||||
[Species.EISCUE]: [
|
[Species.EISCUE]: [
|
||||||
new SpeciesFormChange(Species.EISCUE, "", "no-ice", new SpeciesFormChangeManualTrigger(), true),
|
new SpeciesFormChange(Species.EISCUE, "", "no-ice", new SpeciesFormChangeManualTrigger(), true),
|
||||||
new SpeciesFormChange(Species.EISCUE, "no-ice", "", new SpeciesFormChangeManualTrigger(), true),
|
new SpeciesFormChange(Species.EISCUE, "no-ice", "", new SpeciesFormChangeManualTrigger(), true),
|
||||||
|
],
|
||||||
|
[Species.CRAMORANT]: [
|
||||||
|
new SpeciesFormChange(Species.CRAMORANT, "", "gulping", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() >= .5)),
|
||||||
|
new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)),
|
||||||
|
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeManualTrigger, true),
|
||||||
|
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeManualTrigger, true),
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18666,7 +18666,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 48, Moves.PIKA_PAPOW ],
|
[ 48, Moves.PIKA_PAPOW ],
|
||||||
],
|
],
|
||||||
3: [
|
3: [
|
||||||
[ EVOLVE_MOVE, Moves.METEOR_MASH ],
|
[ 1, Moves.METEOR_MASH ],
|
||||||
[ 1, Moves.TAIL_WHIP ],
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.THUNDER_SHOCK ],
|
[ 1, Moves.THUNDER_SHOCK ],
|
||||||
@ -18690,7 +18690,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 48, Moves.PIKA_PAPOW ],
|
[ 48, Moves.PIKA_PAPOW ],
|
||||||
],
|
],
|
||||||
4: [
|
4: [
|
||||||
[ EVOLVE_MOVE, Moves.ICICLE_CRASH ],
|
[ 1, Moves.ICICLE_CRASH ],
|
||||||
[ 1, Moves.TAIL_WHIP ],
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.THUNDER_SHOCK ],
|
[ 1, Moves.THUNDER_SHOCK ],
|
||||||
@ -18714,7 +18714,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 48, Moves.PIKA_PAPOW ],
|
[ 48, Moves.PIKA_PAPOW ],
|
||||||
],
|
],
|
||||||
5: [
|
5: [
|
||||||
[ EVOLVE_MOVE, Moves.DRAINING_KISS ],
|
[ 1, Moves.DRAINING_KISS ],
|
||||||
[ 1, Moves.TAIL_WHIP ],
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.THUNDER_SHOCK ],
|
[ 1, Moves.THUNDER_SHOCK ],
|
||||||
@ -18738,7 +18738,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 48, Moves.PIKA_PAPOW ],
|
[ 48, Moves.PIKA_PAPOW ],
|
||||||
],
|
],
|
||||||
6: [
|
6: [
|
||||||
[ EVOLVE_MOVE, Moves.ELECTRIC_TERRAIN ],
|
[ 1, Moves.ELECTRIC_TERRAIN ],
|
||||||
[ 1, Moves.TAIL_WHIP ],
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.THUNDER_SHOCK ],
|
[ 1, Moves.THUNDER_SHOCK ],
|
||||||
@ -18762,7 +18762,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 48, Moves.PIKA_PAPOW ],
|
[ 48, Moves.PIKA_PAPOW ],
|
||||||
],
|
],
|
||||||
7: [
|
7: [
|
||||||
[ EVOLVE_MOVE, Moves.FLYING_PRESS ],
|
[ 1, Moves.FLYING_PRESS ],
|
||||||
[ 1, Moves.TAIL_WHIP ],
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.THUNDER_SHOCK ],
|
[ 1, Moves.THUNDER_SHOCK ],
|
||||||
@ -18886,7 +18886,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
},
|
},
|
||||||
[Species.ROTOM]: {
|
[Species.ROTOM]: {
|
||||||
1: [
|
1: [
|
||||||
[ EVOLVE_MOVE, Moves.OVERHEAT ],
|
[ 1, Moves.OVERHEAT ],
|
||||||
[ 1, Moves.DOUBLE_TEAM ],
|
[ 1, Moves.DOUBLE_TEAM ],
|
||||||
[ 1, Moves.ASTONISH ],
|
[ 1, Moves.ASTONISH ],
|
||||||
[ 5, Moves.THUNDER_SHOCK ],
|
[ 5, Moves.THUNDER_SHOCK ],
|
||||||
@ -18902,7 +18902,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 55, Moves.UPROAR ],
|
[ 55, Moves.UPROAR ],
|
||||||
],
|
],
|
||||||
2: [
|
2: [
|
||||||
[ EVOLVE_MOVE, Moves.HYDRO_PUMP ],
|
[ 1, Moves.HYDRO_PUMP ],
|
||||||
[ 1, Moves.DOUBLE_TEAM ],
|
[ 1, Moves.DOUBLE_TEAM ],
|
||||||
[ 1, Moves.ASTONISH ],
|
[ 1, Moves.ASTONISH ],
|
||||||
[ 5, Moves.THUNDER_SHOCK ],
|
[ 5, Moves.THUNDER_SHOCK ],
|
||||||
@ -18918,7 +18918,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 55, Moves.UPROAR ],
|
[ 55, Moves.UPROAR ],
|
||||||
],
|
],
|
||||||
3: [
|
3: [
|
||||||
[ EVOLVE_MOVE, Moves.BLIZZARD ],
|
[ 1, Moves.BLIZZARD ],
|
||||||
[ 1, Moves.DOUBLE_TEAM ],
|
[ 1, Moves.DOUBLE_TEAM ],
|
||||||
[ 1, Moves.ASTONISH ],
|
[ 1, Moves.ASTONISH ],
|
||||||
[ 5, Moves.THUNDER_SHOCK ],
|
[ 5, Moves.THUNDER_SHOCK ],
|
||||||
@ -18934,7 +18934,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 55, Moves.UPROAR ],
|
[ 55, Moves.UPROAR ],
|
||||||
],
|
],
|
||||||
4: [
|
4: [
|
||||||
[ EVOLVE_MOVE, Moves.AIR_SLASH ],
|
[ 1, Moves.AIR_SLASH ],
|
||||||
[ 1, Moves.DOUBLE_TEAM ],
|
[ 1, Moves.DOUBLE_TEAM ],
|
||||||
[ 1, Moves.ASTONISH ],
|
[ 1, Moves.ASTONISH ],
|
||||||
[ 5, Moves.THUNDER_SHOCK ],
|
[ 5, Moves.THUNDER_SHOCK ],
|
||||||
@ -18950,7 +18950,7 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 55, Moves.UPROAR ],
|
[ 55, Moves.UPROAR ],
|
||||||
],
|
],
|
||||||
5: [
|
5: [
|
||||||
[ EVOLVE_MOVE, Moves.LEAF_STORM ],
|
[ 1, Moves.LEAF_STORM ],
|
||||||
[ 1, Moves.DOUBLE_TEAM ],
|
[ 1, Moves.DOUBLE_TEAM ],
|
||||||
[ 1, Moves.ASTONISH ],
|
[ 1, Moves.ASTONISH ],
|
||||||
[ 5, Moves.THUNDER_SHOCK ],
|
[ 5, Moves.THUNDER_SHOCK ],
|
||||||
|
@ -7,12 +7,12 @@ export { StatusEffect };
|
|||||||
export class Status {
|
export class Status {
|
||||||
public effect: StatusEffect;
|
public effect: StatusEffect;
|
||||||
public turnCount: integer;
|
public turnCount: integer;
|
||||||
public cureTurn: integer;
|
public cureTurn: integer | null;
|
||||||
|
|
||||||
constructor(effect: StatusEffect, turnCount: integer = 0, cureTurn?: integer) {
|
constructor(effect: StatusEffect, turnCount: integer = 0, cureTurn?: integer) {
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
this.turnCount = turnCount === undefined ? 0 : turnCount;
|
this.turnCount = turnCount === undefined ? 0 : turnCount;
|
||||||
this.cureTurn = cureTurn;
|
this.cureTurn = cureTurn!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
incrementTurn(): void {
|
incrementTurn(): void {
|
||||||
@ -24,7 +24,7 @@ export class Status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusEffectMessageKey(statusEffect: StatusEffect): string {
|
function getStatusEffectMessageKey(statusEffect: StatusEffect | undefined): string {
|
||||||
switch (statusEffect) {
|
switch (statusEffect) {
|
||||||
case StatusEffect.POISON:
|
case StatusEffect.POISON:
|
||||||
return "statusEffect:poison";
|
return "statusEffect:poison";
|
||||||
@ -43,7 +43,7 @@ function getStatusEffectMessageKey(statusEffect: StatusEffect): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatusEffectObtainText(statusEffect: StatusEffect, pokemonNameWithAffix: string, sourceText?: string): string {
|
export function getStatusEffectObtainText(statusEffect: StatusEffect | undefined, pokemonNameWithAffix: string, sourceText?: string): string {
|
||||||
if (!sourceText) {
|
if (!sourceText) {
|
||||||
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain`as ParseKeys;
|
const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain`as ParseKeys;
|
||||||
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix });
|
||||||
|
@ -3,7 +3,7 @@ import * as Utils from "../utils";
|
|||||||
|
|
||||||
class TrainerNameConfig {
|
class TrainerNameConfig {
|
||||||
public urls: string[];
|
public urls: string[];
|
||||||
public femaleUrls: string[];
|
public femaleUrls: string[] | null;
|
||||||
|
|
||||||
constructor(type: TrainerType, ...urls: string[]) {
|
constructor(type: TrainerType, ...urls: string[]) {
|
||||||
this.urls = urls.length ? urls : [ Utils.toReadableString(TrainerType[type]).replace(/ /g, "_") ];
|
this.urls = urls.length ? urls : [ Utils.toReadableString(TrainerType[type]).replace(/ /g, "_") ];
|
||||||
@ -136,8 +136,11 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
|
|||||||
.then(html => {
|
.then(html => {
|
||||||
console.log(url);
|
console.log(url);
|
||||||
const htmlDoc = parser.parseFromString(html, "text/html");
|
const htmlDoc = parser.parseFromString(html, "text/html");
|
||||||
const trainerListHeader = htmlDoc.querySelector("#Trainer_list").parentElement;
|
const trainerListHeader = htmlDoc.querySelector("#Trainer_list")?.parentElement;
|
||||||
const elements = [...trainerListHeader.parentElement.childNodes];
|
if (!trainerListHeader) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const elements = [...(trainerListHeader?.parentElement?.childNodes ?? [])];
|
||||||
const startChildIndex = elements.indexOf(trainerListHeader);
|
const startChildIndex = elements.indexOf(trainerListHeader);
|
||||||
const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex);
|
const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex);
|
||||||
const tables = elements.filter(t => {
|
const tables = elements.filter(t => {
|
||||||
@ -152,6 +155,9 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam
|
|||||||
const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9);
|
const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9);
|
||||||
for (const row of trainerRows) {
|
for (const row of trainerRows) {
|
||||||
const nameCell = row.firstElementChild;
|
const nameCell = row.firstElementChild;
|
||||||
|
if (!nameCell) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const content = nameCell.innerHTML;
|
const content = nameCell.innerHTML;
|
||||||
if (content.indexOf(" <a ") > -1) {
|
if (content.indexOf(" <a ") > -1) {
|
||||||
const female = /♀/.test(content);
|
const female = /♀/.test(content);
|
||||||
|
@ -499,6 +499,8 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer):
|
|||||||
case Type.STELLAR:
|
case Type.STELLAR:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,7 +103,7 @@ export class Weather {
|
|||||||
const field = scene.getField(true);
|
const field = scene.getField(true);
|
||||||
|
|
||||||
for (const pokemon of field) {
|
for (const pokemon of field) {
|
||||||
let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr)[0];
|
let suppressWeatherEffectAbAttr: SuppressWeatherEffectAbAttr | null = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr)[0];
|
||||||
if (!suppressWeatherEffectAbAttr) {
|
if (!suppressWeatherEffectAbAttr) {
|
||||||
suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr)[0] : null;
|
suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr)[0] : null;
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ export class Weather {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherStartMessage(weatherType: WeatherType): string {
|
export function getWeatherStartMessage(weatherType: WeatherType): string | null {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return i18next.t("weather:sunnyStartMessage");
|
return i18next.t("weather:sunnyStartMessage");
|
||||||
@ -141,7 +141,7 @@ export function getWeatherStartMessage(weatherType: WeatherType): string {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherLapseMessage(weatherType: WeatherType): string {
|
export function getWeatherLapseMessage(weatherType: WeatherType): string | null {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return i18next.t("weather:sunnyLapseMessage");
|
return i18next.t("weather:sunnyLapseMessage");
|
||||||
@ -166,7 +166,7 @@ export function getWeatherLapseMessage(weatherType: WeatherType): string {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string {
|
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SANDSTORM:
|
case WeatherType.SANDSTORM:
|
||||||
return i18next.t("weather:sandstormDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)});
|
return i18next.t("weather:sandstormDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)});
|
||||||
@ -177,7 +177,7 @@ export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokem
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherClearMessage(weatherType: WeatherType): string {
|
export function getWeatherClearMessage(weatherType: WeatherType): string | null {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return i18next.t("weather:sunnyClearMessage");
|
return i18next.t("weather:sunnyClearMessage");
|
||||||
@ -202,7 +202,7 @@ export function getWeatherClearMessage(weatherType: WeatherType): string {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTerrainStartMessage(terrainType: TerrainType): string {
|
export function getTerrainStartMessage(terrainType: TerrainType): string | null {
|
||||||
switch (terrainType) {
|
switch (terrainType) {
|
||||||
case TerrainType.MISTY:
|
case TerrainType.MISTY:
|
||||||
return i18next.t("terrain:mistyStartMessage");
|
return i18next.t("terrain:mistyStartMessage");
|
||||||
@ -212,10 +212,13 @@ export function getTerrainStartMessage(terrainType: TerrainType): string {
|
|||||||
return i18next.t("terrain:grassyStartMessage");
|
return i18next.t("terrain:grassyStartMessage");
|
||||||
case TerrainType.PSYCHIC:
|
case TerrainType.PSYCHIC:
|
||||||
return i18next.t("terrain:psychicStartMessage");
|
return i18next.t("terrain:psychicStartMessage");
|
||||||
|
default:
|
||||||
|
console.warn("getTerrainStartMessage not defined. Using default null");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTerrainClearMessage(terrainType: TerrainType): string {
|
export function getTerrainClearMessage(terrainType: TerrainType): string | null {
|
||||||
switch (terrainType) {
|
switch (terrainType) {
|
||||||
case TerrainType.MISTY:
|
case TerrainType.MISTY:
|
||||||
return i18next.t("terrain:mistyClearMessage");
|
return i18next.t("terrain:mistyClearMessage");
|
||||||
@ -225,6 +228,9 @@ export function getTerrainClearMessage(terrainType: TerrainType): string {
|
|||||||
return i18next.t("terrain:grassyClearMessage");
|
return i18next.t("terrain:grassyClearMessage");
|
||||||
case TerrainType.PSYCHIC:
|
case TerrainType.PSYCHIC:
|
||||||
return i18next.t("terrain:psychicClearMessage");
|
return i18next.t("terrain:psychicClearMessage");
|
||||||
|
default:
|
||||||
|
console.warn("getTerrainClearMessage not defined. Using default null");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export class EggHatchPhase extends Phase {
|
|||||||
|
|
||||||
this.scene.gameData.eggs.splice(eggIndex, 1);
|
this.scene.gameData.eggs.splice(eggIndex, 1);
|
||||||
|
|
||||||
this.scene.fadeOutBgm(null, false);
|
this.scene.fadeOutBgm(undefined, false);
|
||||||
|
|
||||||
this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler;
|
this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler;
|
||||||
|
|
||||||
@ -234,8 +234,8 @@ export class EggHatchPhase extends Phase {
|
|||||||
ease: "Sine.easeInOut",
|
ease: "Sine.easeInOut",
|
||||||
duration: 250,
|
duration: 250,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
count++;
|
count!++;
|
||||||
if (count < repeatCount) {
|
if (count! < repeatCount!) { // we know they are defined
|
||||||
return this.doEggShake(intensity, repeatCount, count).then(() => resolve());
|
return this.doEggShake(intensity, repeatCount, count).then(() => resolve());
|
||||||
}
|
}
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
@ -347,7 +347,7 @@ export class EggHatchPhase extends Phase {
|
|||||||
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
|
||||||
this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => {
|
this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => {
|
||||||
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => {
|
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => {
|
||||||
this.scene.ui.showText(null, 0);
|
this.scene.ui.showText("", 0);
|
||||||
this.end();
|
this.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -447,6 +447,6 @@ export class EggHatchPhase extends Phase {
|
|||||||
|
|
||||||
}, this.egg.id, EGG_SEED.toString());
|
}, this.egg.id, EGG_SEED.toString());
|
||||||
|
|
||||||
return ret;
|
return ret!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,5 +21,6 @@ export enum ArenaTagType {
|
|||||||
MAT_BLOCK = "MAT_BLOCK",
|
MAT_BLOCK = "MAT_BLOCK",
|
||||||
CRAFTY_SHIELD = "CRAFTY_SHIELD",
|
CRAFTY_SHIELD = "CRAFTY_SHIELD",
|
||||||
TAILWIND = "TAILWIND",
|
TAILWIND = "TAILWIND",
|
||||||
HAPPY_HOUR = "HAPPY_HOUR"
|
HAPPY_HOUR = "HAPPY_HOUR",
|
||||||
|
NO_CRIT = "NO_CRIT"
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ export enum BattlerTagType {
|
|||||||
FIRE_BOOST = "FIRE_BOOST",
|
FIRE_BOOST = "FIRE_BOOST",
|
||||||
CRIT_BOOST = "CRIT_BOOST",
|
CRIT_BOOST = "CRIT_BOOST",
|
||||||
ALWAYS_CRIT = "ALWAYS_CRIT",
|
ALWAYS_CRIT = "ALWAYS_CRIT",
|
||||||
NO_CRIT = "NO_CRIT",
|
|
||||||
IGNORE_ACCURACY = "IGNORE_ACCURACY",
|
IGNORE_ACCURACY = "IGNORE_ACCURACY",
|
||||||
BYPASS_SLEEP = "BYPASS_SLEEP",
|
BYPASS_SLEEP = "BYPASS_SLEEP",
|
||||||
IGNORE_FLYING = "IGNORE_FLYING",
|
IGNORE_FLYING = "IGNORE_FLYING",
|
||||||
@ -64,5 +63,10 @@ export enum BattlerTagType {
|
|||||||
STOCKPILING = "STOCKPILING",
|
STOCKPILING = "STOCKPILING",
|
||||||
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
||||||
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
||||||
DISABLED = "DISABLED"
|
DISABLED = "DISABLED",
|
||||||
|
IGNORE_GHOST = "IGNORE_GHOST",
|
||||||
|
IGNORE_DARK = "IGNORE_DARK",
|
||||||
|
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
|
||||||
|
GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU",
|
||||||
|
BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING"
|
||||||
}
|
}
|
||||||
|
@ -1,215 +1,223 @@
|
|||||||
|
|
||||||
export enum TrainerType {
|
export enum TrainerType {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
|
|
||||||
ACE_TRAINER,
|
ACE_TRAINER,
|
||||||
ARTIST,
|
ARTIST,
|
||||||
BACKERS,
|
BACKERS,
|
||||||
BACKPACKER,
|
BACKPACKER,
|
||||||
BAKER,
|
BAKER,
|
||||||
BEAUTY,
|
BEAUTY,
|
||||||
BIKER,
|
BIKER,
|
||||||
BLACK_BELT,
|
BLACK_BELT,
|
||||||
BREEDER,
|
BREEDER,
|
||||||
CLERK,
|
CLERK,
|
||||||
CYCLIST,
|
CYCLIST,
|
||||||
DANCER,
|
DANCER,
|
||||||
DEPOT_AGENT,
|
DEPOT_AGENT,
|
||||||
DOCTOR,
|
DOCTOR,
|
||||||
FIREBREATHER,
|
FIREBREATHER,
|
||||||
FISHERMAN,
|
FISHERMAN,
|
||||||
GUITARIST,
|
GUITARIST,
|
||||||
HARLEQUIN,
|
HARLEQUIN,
|
||||||
HIKER,
|
HIKER,
|
||||||
HOOLIGANS,
|
HOOLIGANS,
|
||||||
HOOPSTER,
|
HOOPSTER,
|
||||||
INFIELDER,
|
INFIELDER,
|
||||||
JANITOR,
|
JANITOR,
|
||||||
LINEBACKER,
|
LINEBACKER,
|
||||||
MAID,
|
MAID,
|
||||||
MUSICIAN,
|
MUSICIAN,
|
||||||
HEX_MANIAC,
|
HEX_MANIAC,
|
||||||
NURSERY_AIDE,
|
NURSERY_AIDE,
|
||||||
OFFICER,
|
OFFICER,
|
||||||
PARASOL_LADY,
|
PARASOL_LADY,
|
||||||
PILOT,
|
PILOT,
|
||||||
POKEFAN,
|
POKEFAN,
|
||||||
PRESCHOOLER,
|
PRESCHOOLER,
|
||||||
PSYCHIC,
|
PSYCHIC,
|
||||||
RANGER,
|
RANGER,
|
||||||
RICH,
|
RICH,
|
||||||
RICH_KID,
|
RICH_KID,
|
||||||
ROUGHNECK,
|
ROUGHNECK,
|
||||||
SAILOR,
|
SAILOR,
|
||||||
SCIENTIST,
|
SCIENTIST,
|
||||||
SMASHER,
|
SMASHER,
|
||||||
SNOW_WORKER,
|
SNOW_WORKER,
|
||||||
STRIKER,
|
STRIKER,
|
||||||
SCHOOL_KID,
|
SCHOOL_KID,
|
||||||
SWIMMER,
|
SWIMMER,
|
||||||
TWINS,
|
TWINS,
|
||||||
VETERAN,
|
VETERAN,
|
||||||
WAITER,
|
WAITER,
|
||||||
WORKER,
|
WORKER,
|
||||||
YOUNGSTER,
|
YOUNGSTER,
|
||||||
ROCKET_GRUNT,
|
ROCKET_GRUNT,
|
||||||
ROCKET_ADMIN,
|
ARCHER,
|
||||||
MAGMA_GRUNT,
|
ARIANA,
|
||||||
MAGMA_ADMIN,
|
PROTON,
|
||||||
AQUA_GRUNT,
|
PETREL,
|
||||||
AQUA_ADMIN,
|
MAGMA_GRUNT,
|
||||||
GALACTIC_GRUNT,
|
TABITHA,
|
||||||
GALACTIC_ADMIN,
|
COURTNEY,
|
||||||
PLASMA_GRUNT,
|
AQUA_GRUNT,
|
||||||
PLASMA_SAGE,
|
MATT,
|
||||||
FLARE_GRUNT,
|
SHELLY,
|
||||||
FLARE_ADMIN,
|
GALACTIC_GRUNT,
|
||||||
ROCKET_BOSS_GIOVANNI_1,
|
JUPITER,
|
||||||
ROCKET_BOSS_GIOVANNI_2,
|
MARS,
|
||||||
MAXIE,
|
SATURN,
|
||||||
MAXIE_2,
|
PLASMA_GRUNT,
|
||||||
ARCHIE,
|
ZINZOLIN,
|
||||||
ARCHIE_2,
|
ROOD,
|
||||||
CYRUS,
|
FLARE_GRUNT,
|
||||||
CYRUS_2,
|
BRYONY,
|
||||||
GHETSIS,
|
XEROSIC,
|
||||||
GHETSIS_2,
|
ROCKET_BOSS_GIOVANNI_1,
|
||||||
LYSANDRE,
|
ROCKET_BOSS_GIOVANNI_2,
|
||||||
LYSANDRE_2,
|
MAXIE,
|
||||||
|
MAXIE_2,
|
||||||
|
ARCHIE,
|
||||||
|
ARCHIE_2,
|
||||||
|
CYRUS,
|
||||||
|
CYRUS_2,
|
||||||
|
GHETSIS,
|
||||||
|
GHETSIS_2,
|
||||||
|
LYSANDRE,
|
||||||
|
LYSANDRE_2,
|
||||||
|
|
||||||
BROCK = 200,
|
BROCK = 200,
|
||||||
MISTY,
|
MISTY,
|
||||||
LT_SURGE,
|
LT_SURGE,
|
||||||
ERIKA,
|
ERIKA,
|
||||||
JANINE,
|
JANINE,
|
||||||
SABRINA,
|
SABRINA,
|
||||||
BLAINE,
|
BLAINE,
|
||||||
GIOVANNI,
|
GIOVANNI,
|
||||||
FALKNER,
|
FALKNER,
|
||||||
BUGSY,
|
BUGSY,
|
||||||
WHITNEY,
|
WHITNEY,
|
||||||
MORTY,
|
MORTY,
|
||||||
CHUCK,
|
CHUCK,
|
||||||
JASMINE,
|
JASMINE,
|
||||||
PRYCE,
|
PRYCE,
|
||||||
CLAIR,
|
CLAIR,
|
||||||
ROXANNE,
|
ROXANNE,
|
||||||
BRAWLY,
|
BRAWLY,
|
||||||
WATTSON,
|
WATTSON,
|
||||||
FLANNERY,
|
FLANNERY,
|
||||||
NORMAN,
|
NORMAN,
|
||||||
WINONA,
|
WINONA,
|
||||||
TATE,
|
TATE,
|
||||||
LIZA,
|
LIZA,
|
||||||
JUAN,
|
JUAN,
|
||||||
ROARK,
|
ROARK,
|
||||||
GARDENIA,
|
GARDENIA,
|
||||||
MAYLENE,
|
MAYLENE,
|
||||||
CRASHER_WAKE,
|
CRASHER_WAKE,
|
||||||
FANTINA,
|
FANTINA,
|
||||||
BYRON,
|
BYRON,
|
||||||
CANDICE,
|
CANDICE,
|
||||||
VOLKNER,
|
VOLKNER,
|
||||||
CILAN,
|
CILAN,
|
||||||
CHILI,
|
CHILI,
|
||||||
CRESS,
|
CRESS,
|
||||||
CHEREN,
|
CHEREN,
|
||||||
LENORA,
|
LENORA,
|
||||||
ROXIE,
|
ROXIE,
|
||||||
BURGH,
|
BURGH,
|
||||||
ELESA,
|
ELESA,
|
||||||
CLAY,
|
CLAY,
|
||||||
SKYLA,
|
SKYLA,
|
||||||
BRYCEN,
|
BRYCEN,
|
||||||
DRAYDEN,
|
DRAYDEN,
|
||||||
MARLON,
|
MARLON,
|
||||||
VIOLA,
|
VIOLA,
|
||||||
GRANT,
|
GRANT,
|
||||||
KORRINA,
|
KORRINA,
|
||||||
RAMOS,
|
RAMOS,
|
||||||
CLEMONT,
|
CLEMONT,
|
||||||
VALERIE,
|
VALERIE,
|
||||||
OLYMPIA,
|
OLYMPIA,
|
||||||
WULFRIC,
|
WULFRIC,
|
||||||
MILO,
|
MILO,
|
||||||
NESSA,
|
NESSA,
|
||||||
KABU,
|
KABU,
|
||||||
BEA,
|
BEA,
|
||||||
ALLISTER,
|
ALLISTER,
|
||||||
OPAL,
|
OPAL,
|
||||||
BEDE,
|
BEDE,
|
||||||
GORDIE,
|
GORDIE,
|
||||||
MELONY,
|
MELONY,
|
||||||
PIERS,
|
PIERS,
|
||||||
MARNIE,
|
MARNIE,
|
||||||
RAIHAN,
|
RAIHAN,
|
||||||
KATY,
|
KATY,
|
||||||
BRASSIUS,
|
BRASSIUS,
|
||||||
IONO,
|
IONO,
|
||||||
KOFU,
|
KOFU,
|
||||||
LARRY,
|
LARRY,
|
||||||
RYME,
|
RYME,
|
||||||
TULIP,
|
TULIP,
|
||||||
GRUSHA,
|
GRUSHA,
|
||||||
LORELEI = 300,
|
LORELEI = 300,
|
||||||
BRUNO,
|
BRUNO,
|
||||||
AGATHA,
|
AGATHA,
|
||||||
LANCE,
|
LANCE,
|
||||||
WILL,
|
WILL,
|
||||||
KOGA,
|
KOGA,
|
||||||
KAREN,
|
KAREN,
|
||||||
SIDNEY,
|
SIDNEY,
|
||||||
PHOEBE,
|
PHOEBE,
|
||||||
GLACIA,
|
GLACIA,
|
||||||
DRAKE,
|
DRAKE,
|
||||||
AARON,
|
AARON,
|
||||||
BERTHA,
|
BERTHA,
|
||||||
FLINT,
|
FLINT,
|
||||||
LUCIAN,
|
LUCIAN,
|
||||||
SHAUNTAL,
|
SHAUNTAL,
|
||||||
MARSHAL,
|
MARSHAL,
|
||||||
GRIMSLEY,
|
GRIMSLEY,
|
||||||
CAITLIN,
|
CAITLIN,
|
||||||
MALVA,
|
MALVA,
|
||||||
SIEBOLD,
|
SIEBOLD,
|
||||||
WIKSTROM,
|
WIKSTROM,
|
||||||
DRASNA,
|
DRASNA,
|
||||||
HALA,
|
HALA,
|
||||||
MOLAYNE,
|
MOLAYNE,
|
||||||
OLIVIA,
|
OLIVIA,
|
||||||
ACEROLA,
|
ACEROLA,
|
||||||
KAHILI,
|
KAHILI,
|
||||||
MARNIE_ELITE,
|
MARNIE_ELITE,
|
||||||
NESSA_ELITE,
|
NESSA_ELITE,
|
||||||
BEA_ELITE,
|
BEA_ELITE,
|
||||||
ALLISTER_ELITE,
|
ALLISTER_ELITE,
|
||||||
RAIHAN_ELITE,
|
RAIHAN_ELITE,
|
||||||
RIKA,
|
RIKA,
|
||||||
POPPY,
|
POPPY,
|
||||||
LARRY_ELITE,
|
LARRY_ELITE,
|
||||||
HASSEL,
|
HASSEL,
|
||||||
CRISPIN,
|
CRISPIN,
|
||||||
AMARYS,
|
AMARYS,
|
||||||
LACEY,
|
LACEY,
|
||||||
DRAYTON,
|
DRAYTON,
|
||||||
BLUE = 350,
|
BLUE = 350,
|
||||||
RED,
|
RED,
|
||||||
LANCE_CHAMPION,
|
LANCE_CHAMPION,
|
||||||
STEVEN,
|
STEVEN,
|
||||||
WALLACE,
|
WALLACE,
|
||||||
CYNTHIA,
|
CYNTHIA,
|
||||||
ALDER,
|
ALDER,
|
||||||
IRIS,
|
IRIS,
|
||||||
DIANTHA,
|
DIANTHA,
|
||||||
HAU,
|
HAU,
|
||||||
LEON,
|
LEON,
|
||||||
GEETA,
|
GEETA,
|
||||||
NEMONA,
|
NEMONA,
|
||||||
KIERAN,
|
KIERAN,
|
||||||
RIVAL = 375,
|
RIVAL = 375,
|
||||||
RIVAL_2,
|
RIVAL_2,
|
||||||
RIVAL_3,
|
RIVAL_3,
|
||||||
RIVAL_4,
|
RIVAL_4,
|
||||||
RIVAL_5,
|
RIVAL_5,
|
||||||
RIVAL_6
|
RIVAL_6
|
||||||
}
|
}
|
||||||
|
@ -81,8 +81,8 @@ export class TagAddedEvent extends ArenaEvent {
|
|||||||
|
|
||||||
this.arenaTagType = arenaTagType;
|
this.arenaTagType = arenaTagType;
|
||||||
this.arenaTagSide = arenaTagSide;
|
this.arenaTagSide = arenaTagSide;
|
||||||
this.arenaTagLayers = arenaTagLayers;
|
this.arenaTagLayers = arenaTagLayers!; // TODO: is this bang correct?
|
||||||
this.arenaTagMaxLayers = arenaTagMaxLayers;
|
this.arenaTagMaxLayers = arenaTagMaxLayers!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +16,7 @@ export class EvolutionPhase extends Phase {
|
|||||||
protected pokemon: PlayerPokemon;
|
protected pokemon: PlayerPokemon;
|
||||||
protected lastLevel: integer;
|
protected lastLevel: integer;
|
||||||
|
|
||||||
private evolution: SpeciesFormEvolution;
|
private evolution: SpeciesFormEvolution | null;
|
||||||
|
|
||||||
protected evolutionContainer: Phaser.GameObjects.Container;
|
protected evolutionContainer: Phaser.GameObjects.Container;
|
||||||
protected evolutionBaseBg: Phaser.GameObjects.Image;
|
protected evolutionBaseBg: Phaser.GameObjects.Image;
|
||||||
@ -28,7 +28,7 @@ export class EvolutionPhase extends Phase {
|
|||||||
protected pokemonEvoSprite: Phaser.GameObjects.Sprite;
|
protected pokemonEvoSprite: Phaser.GameObjects.Sprite;
|
||||||
protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
|
protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
constructor(scene: BattleScene, pokemon: PlayerPokemon, evolution: SpeciesFormEvolution, lastLevel: integer) {
|
constructor(scene: BattleScene, pokemon: PlayerPokemon, evolution: SpeciesFormEvolution | null, lastLevel: integer) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
|
||||||
this.pokemon = pokemon;
|
this.pokemon = pokemon;
|
||||||
@ -53,7 +53,7 @@ export class EvolutionPhase extends Phase {
|
|||||||
return this.end();
|
return this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.fadeOutBgm(null, false);
|
this.scene.fadeOutBgm(undefined, false);
|
||||||
|
|
||||||
const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
|
const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ export class EvolutionPhase extends Phase {
|
|||||||
this.scene.ui.showText(i18next.t("menu:stoppedEvolving", { pokemonName: preName }), null, () => {
|
this.scene.ui.showText(i18next.t("menu:stoppedEvolving", { pokemonName: preName }), null, () => {
|
||||||
this.scene.ui.showText(i18next.t("menu:pauseEvolutionsQuestion", { pokemonName: preName }), null, () => {
|
this.scene.ui.showText(i18next.t("menu:pauseEvolutionsQuestion", { pokemonName: preName }), null, () => {
|
||||||
const end = () => {
|
const end = () => {
|
||||||
this.scene.ui.showText(null, 0);
|
this.scene.ui.showText("", 0);
|
||||||
this.scene.playBgm();
|
this.scene.playBgm();
|
||||||
evolvedPokemon.destroy();
|
evolvedPokemon.destroy();
|
||||||
this.end();
|
this.end();
|
||||||
|
@ -25,8 +25,8 @@ import { TrainerType } from "#enums/trainer-type";
|
|||||||
export class Arena {
|
export class Arena {
|
||||||
public scene: BattleScene;
|
public scene: BattleScene;
|
||||||
public biomeType: Biome;
|
public biomeType: Biome;
|
||||||
public weather: Weather;
|
public weather: Weather | null;
|
||||||
public terrain: Terrain;
|
public terrain: Terrain | null;
|
||||||
public tags: ArenaTag[];
|
public tags: ArenaTag[];
|
||||||
public bgm: string;
|
public bgm: string;
|
||||||
public ignoreAbilities: boolean;
|
public ignoreAbilities: boolean;
|
||||||
@ -121,7 +121,7 @@ export class Arena {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = getPokemonSpecies(species);
|
ret = getPokemonSpecies(species!);
|
||||||
|
|
||||||
if (ret.subLegendary || ret.legendary || ret.mythical) {
|
if (ret.subLegendary || ret.legendary || ret.mythical) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
@ -292,7 +292,7 @@ export class Arena {
|
|||||||
trySetWeatherOverride(weather: WeatherType): boolean {
|
trySetWeatherOverride(weather: WeatherType): boolean {
|
||||||
this.weather = new Weather(weather, 0);
|
this.weather = new Weather(weather, 0);
|
||||||
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
||||||
this.scene.queueMessage(getWeatherStartMessage(weather));
|
this.scene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,13 +314,13 @@ export class Arena {
|
|||||||
const oldWeatherType = this.weather?.weatherType || WeatherType.NONE;
|
const oldWeatherType = this.weather?.weatherType || WeatherType.NONE;
|
||||||
|
|
||||||
this.weather = weather ? new Weather(weather, hasPokemonSource ? 5 : 0) : null;
|
this.weather = weather ? new Weather(weather, hasPokemonSource ? 5 : 0) : null;
|
||||||
this.eventTarget.dispatchEvent(new WeatherChangedEvent(oldWeatherType, this.weather?.weatherType, this.weather?.turnsLeft));
|
this.eventTarget.dispatchEvent(new WeatherChangedEvent(oldWeatherType, this.weather?.weatherType!, this.weather?.turnsLeft!)); // TODO: is this bang correct?
|
||||||
|
|
||||||
if (this.weather) {
|
if (this.weather) {
|
||||||
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
||||||
this.scene.queueMessage(getWeatherStartMessage(weather));
|
this.scene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
|
||||||
} else {
|
} else {
|
||||||
this.scene.queueMessage(getWeatherClearMessage(oldWeatherType));
|
this.scene.queueMessage(getWeatherClearMessage(oldWeatherType)!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
||||||
@ -339,15 +339,15 @@ export class Arena {
|
|||||||
const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE;
|
const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE;
|
||||||
|
|
||||||
this.terrain = terrain ? new Terrain(terrain, hasPokemonSource ? 5 : 0) : null;
|
this.terrain = terrain ? new Terrain(terrain, hasPokemonSource ? 5 : 0) : null;
|
||||||
this.eventTarget.dispatchEvent(new TerrainChangedEvent(oldTerrainType,this.terrain?.terrainType, this.terrain?.turnsLeft));
|
this.eventTarget.dispatchEvent(new TerrainChangedEvent(oldTerrainType,this.terrain?.terrainType!, this.terrain?.turnsLeft!)); // TODO: are those bangs correct?
|
||||||
|
|
||||||
if (this.terrain) {
|
if (this.terrain) {
|
||||||
if (!ignoreAnim) {
|
if (!ignoreAnim) {
|
||||||
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)));
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)));
|
||||||
}
|
}
|
||||||
this.scene.queueMessage(getTerrainStartMessage(terrain));
|
this.scene.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct?
|
||||||
} else {
|
} else {
|
||||||
this.scene.queueMessage(getTerrainClearMessage(oldTerrainType));
|
this.scene.queueMessage(getTerrainClearMessage(oldTerrainType)!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => {
|
||||||
@ -554,7 +554,7 @@ export class Arena {
|
|||||||
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
||||||
const existingTag = this.getTagOnSide(tagType, side);
|
const existingTag = this.getTagOnSide(tagType, side);
|
||||||
if (existingTag) {
|
if (existingTag) {
|
||||||
existingTag.onOverlap(this);
|
existingTag.onOverlap(this);
|
||||||
@ -568,21 +568,23 @@ export class Arena {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
||||||
this.tags.push(newTag);
|
if (newTag) {
|
||||||
newTag.onAdd(this, quiet);
|
this.tags.push(newTag);
|
||||||
|
newTag.onAdd(this, quiet);
|
||||||
|
|
||||||
const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {};
|
const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {};
|
||||||
|
|
||||||
this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount, layers, maxLayers));
|
this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount, layers, maxLayers));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTag(tagType: ArenaTagType | Constructor<ArenaTag>): ArenaTag {
|
getTag(tagType: ArenaTagType | Constructor<ArenaTag>): ArenaTag | undefined {
|
||||||
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag {
|
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
|
||||||
return typeof(tagType) === "string"
|
return typeof(tagType) === "string"
|
||||||
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
||||||
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
||||||
@ -724,6 +726,9 @@ export class Arena {
|
|||||||
return 0.000;
|
return 0.000;
|
||||||
case Biome.SNOWY_FOREST:
|
case Biome.SNOWY_FOREST:
|
||||||
return 3.047;
|
return 3.047;
|
||||||
|
default:
|
||||||
|
console.warn(`missing bgm loop-point for biome "${Biome[this.biomeType]}" (=${this.biomeType})`);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -777,12 +782,12 @@ export class ArenaBase extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
this.base = scene.addFieldSprite(0, 0, "plains_a", null, 1);
|
this.base = scene.addFieldSprite(0, 0, "plains_a", undefined, 1);
|
||||||
this.base.setOrigin(0, 0);
|
this.base.setOrigin(0, 0);
|
||||||
|
|
||||||
this.props = !player ?
|
this.props = !player ?
|
||||||
new Array(3).fill(null).map(() => {
|
new Array(3).fill(null).map(() => {
|
||||||
const ret = scene.addFieldSprite(0, 0, "plains_b", null, 1);
|
const ret = scene.addFieldSprite(0, 0, "plains_b", undefined, 1);
|
||||||
ret.setOrigin(0, 0);
|
ret.setOrigin(0, 0);
|
||||||
ret.setVisible(false);
|
ret.setVisible(false);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3,6 +3,8 @@ import Pokemon, { DamageResult, HitResult } from "./pokemon";
|
|||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
|
|
||||||
|
type TextAndShadowArr = [ string | null, string | null ];
|
||||||
|
|
||||||
export default class DamageNumberHandler {
|
export default class DamageNumberHandler {
|
||||||
private damageNumbers: Map<BattlerIndex, Phaser.GameObjects.Text[]>;
|
private damageNumbers: Map<BattlerIndex, Phaser.GameObjects.Text[]>;
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ export default class DamageNumberHandler {
|
|||||||
damageNumber.setOrigin(0.5, 1);
|
damageNumber.setOrigin(0.5, 1);
|
||||||
damageNumber.setScale(baseScale);
|
damageNumber.setScale(baseScale);
|
||||||
|
|
||||||
let [ textColor, shadowColor ] = [ null, null ];
|
let [ textColor, shadowColor ] : TextAndShadowArr = [ null, null ];
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case HitResult.SUPER_EFFECTIVE:
|
case HitResult.SUPER_EFFECTIVE:
|
||||||
@ -62,12 +64,12 @@ export default class DamageNumberHandler {
|
|||||||
this.damageNumbers.set(battlerIndex, []);
|
this.damageNumbers.set(battlerIndex, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
const yOffset = this.damageNumbers.get(battlerIndex).length * -10;
|
const yOffset = this.damageNumbers.get(battlerIndex)!.length * -10;
|
||||||
if (yOffset) {
|
if (yOffset) {
|
||||||
damageNumber.y += yOffset;
|
damageNumber.y += yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.damageNumbers.get(battlerIndex).push(damageNumber);
|
this.damageNumbers.get(battlerIndex)!.push(damageNumber);
|
||||||
|
|
||||||
if (scene.damageNumbersMode === 1) {
|
if (scene.damageNumbersMode === 1) {
|
||||||
scene.tweens.add({
|
scene.tweens.add({
|
||||||
@ -83,7 +85,7 @@ export default class DamageNumberHandler {
|
|||||||
alpha: 0,
|
alpha: 0,
|
||||||
ease: "Sine.easeIn",
|
ease: "Sine.easeIn",
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.damageNumbers.get(battlerIndex).splice(this.damageNumbers.get(battlerIndex).indexOf(damageNumber), 1);
|
this.damageNumbers.get(battlerIndex)!.splice(this.damageNumbers.get(battlerIndex)!.indexOf(damageNumber), 1);
|
||||||
damageNumber.destroy(true);
|
damageNumber.destroy(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -167,7 +169,7 @@ export default class DamageNumberHandler {
|
|||||||
delay: Utils.fixedInt(500),
|
delay: Utils.fixedInt(500),
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.damageNumbers.get(battlerIndex).splice(this.damageNumbers.get(battlerIndex).indexOf(damageNumber), 1);
|
this.damageNumbers.get(battlerIndex)!.splice(this.damageNumbers.get(battlerIndex)!.indexOf(damageNumber), 1);
|
||||||
damageNumber.destroy(true);
|
damageNumber.destroy(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export default class PokemonSpriteSparkleHandler {
|
|||||||
const ratioX = s.width / width;
|
const ratioX = s.width / width;
|
||||||
const ratioY = s.height / height;
|
const ratioY = s.height / height;
|
||||||
const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE");
|
const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE");
|
||||||
if (pixel.alpha) {
|
if (pixel?.alpha) {
|
||||||
const [ xOffset, yOffset ] = [ -s.originX * s.width, -s.originY * s.height];
|
const [ xOffset, yOffset ] = [ -s.originX * s.width, -s.originY * s.height];
|
||||||
const sparkle = (s.scene as BattleScene).addFieldSprite(((pokemon?.x || 0) + s.x + pixelX * ratioX + xOffset), ((pokemon?.y || 0) + s.y + pixelY * ratioY + yOffset), "tera_sparkle");
|
const sparkle = (s.scene as BattleScene).addFieldSprite(((pokemon?.x || 0) + s.x + pixelX * ratioX + xOffset), ((pokemon?.y || 0) + s.y + pixelY * ratioY + yOffset), "tera_sparkle");
|
||||||
sparkle.pipelineData["ignoreTimeTint"] = s.pipelineData["ignoreTimeTint"];
|
sparkle.pipelineData["ignoreTimeTint"] = s.pipelineData["ignoreTimeTint"];
|
||||||
|
@ -22,7 +22,7 @@ import { BattleStat } from "../data/battle-stat";
|
|||||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, DisablingBattlerTag } from "../data/battler-tags";
|
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, DisablingBattlerTag } from "../data/battler-tags";
|
||||||
import { WeatherType } from "../data/weather";
|
import { WeatherType } from "../data/weather";
|
||||||
import { TempBattleStat } from "../data/temp-battle-stat";
|
import { TempBattleStat } from "../data/temp-battle-stat";
|
||||||
import { ArenaTagSide, WeakenMoveScreenTag } from "../data/arena-tag";
|
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag";
|
||||||
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr } from "../data/ability";
|
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr } from "../data/ability";
|
||||||
import PokemonData from "../system/pokemon-data";
|
import PokemonData from "../system/pokemon-data";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
@ -79,8 +79,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
public ivs: integer[];
|
public ivs: integer[];
|
||||||
public nature: Nature;
|
public nature: Nature;
|
||||||
public natureOverride: Nature | -1;
|
public natureOverride: Nature | -1;
|
||||||
public moveset: PokemonMove[];
|
public moveset: (PokemonMove | null)[];
|
||||||
public status: Status;
|
public status: Status | null;
|
||||||
public friendship: integer;
|
public friendship: integer;
|
||||||
public metLevel: integer;
|
public metLevel: integer;
|
||||||
public metBiome: Biome | -1;
|
public metBiome: Biome | -1;
|
||||||
@ -88,8 +88,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
public luck: integer;
|
public luck: integer;
|
||||||
public pauseEvolutions: boolean;
|
public pauseEvolutions: boolean;
|
||||||
public pokerus: boolean;
|
public pokerus: boolean;
|
||||||
|
public wildFlee: boolean;
|
||||||
|
|
||||||
public fusionSpecies: PokemonSpecies;
|
public fusionSpecies: PokemonSpecies | null;
|
||||||
public fusionFormIndex: integer;
|
public fusionFormIndex: integer;
|
||||||
public fusionAbilityIndex: integer;
|
public fusionAbilityIndex: integer;
|
||||||
public fusionShiny: boolean;
|
public fusionShiny: boolean;
|
||||||
@ -97,7 +98,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
public fusionGender: Gender;
|
public fusionGender: Gender;
|
||||||
public fusionLuck: integer;
|
public fusionLuck: integer;
|
||||||
|
|
||||||
private summonDataPrimer: PokemonSummonData;
|
private summonDataPrimer: PokemonSummonData | null;
|
||||||
|
|
||||||
public summonData: PokemonSummonData;
|
public summonData: PokemonSummonData;
|
||||||
public battleData: PokemonBattleData;
|
public battleData: PokemonBattleData;
|
||||||
@ -107,7 +108,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
public fieldPosition: FieldPosition;
|
public fieldPosition: FieldPosition;
|
||||||
|
|
||||||
public maskEnabled: boolean;
|
public maskEnabled: boolean;
|
||||||
public maskSprite: Phaser.GameObjects.Sprite;
|
public maskSprite: Phaser.GameObjects.Sprite | null;
|
||||||
|
|
||||||
private shinySparkle: Phaser.GameObjects.Sprite;
|
private shinySparkle: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
@ -129,6 +130,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.species = species;
|
this.species = species;
|
||||||
this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL;
|
this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
this.wildFlee = false;
|
||||||
|
|
||||||
// Determine the ability index
|
// Determine the ability index
|
||||||
if (abilityIndex !== undefined) {
|
if (abilityIndex !== undefined) {
|
||||||
this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined
|
this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined
|
||||||
@ -169,7 +172,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.nickname = dataSource.nickname;
|
this.nickname = dataSource.nickname;
|
||||||
this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1;
|
this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1;
|
||||||
this.moveset = dataSource.moveset;
|
this.moveset = dataSource.moveset;
|
||||||
this.status = dataSource.status;
|
this.status = dataSource.status!; // TODO: is this bang correct?
|
||||||
this.friendship = dataSource.friendship !== undefined ? dataSource.friendship : this.species.baseFriendship;
|
this.friendship = dataSource.friendship !== undefined ? dataSource.friendship : this.species.baseFriendship;
|
||||||
this.metLevel = dataSource.metLevel || 5;
|
this.metLevel = dataSource.metLevel || 5;
|
||||||
this.luck = dataSource.luck;
|
this.luck = dataSource.luck;
|
||||||
@ -177,7 +180,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true));
|
this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true));
|
||||||
this.pauseEvolutions = dataSource.pauseEvolutions;
|
this.pauseEvolutions = dataSource.pauseEvolutions;
|
||||||
this.pokerus = !!dataSource.pokerus;
|
this.pokerus = !!dataSource.pokerus;
|
||||||
this.fusionSpecies = dataSource.fusionSpecies instanceof PokemonSpecies ? dataSource.fusionSpecies : getPokemonSpecies(dataSource.fusionSpecies);
|
this.fusionSpecies = dataSource.fusionSpecies instanceof PokemonSpecies ? dataSource.fusionSpecies : dataSource.fusionSpecies ? getPokemonSpecies(dataSource.fusionSpecies) : null;
|
||||||
this.fusionFormIndex = dataSource.fusionFormIndex;
|
this.fusionFormIndex = dataSource.fusionFormIndex;
|
||||||
this.fusionAbilityIndex = dataSource.fusionAbilityIndex;
|
this.fusionAbilityIndex = dataSource.fusionAbilityIndex;
|
||||||
this.fusionShiny = dataSource.fusionShiny;
|
this.fusionShiny = dataSource.fusionShiny;
|
||||||
@ -298,14 +301,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this pokemon is both not fainted and allowed to be in battle.
|
* Check if this pokemon is both not fainted (or a fled wild pokemon) and allowed to be in battle.
|
||||||
* This is frequently a better alternative to {@link isFainted}
|
* This is frequently a better alternative to {@link isFainted}
|
||||||
* @returns {boolean} True if pokemon is allowed in battle
|
* @returns {boolean} True if pokemon is allowed in battle
|
||||||
*/
|
*/
|
||||||
isAllowedInBattle(): boolean {
|
isAllowedInBattle(): boolean {
|
||||||
const challengeAllowed = new Utils.BooleanHolder(true);
|
const challengeAllowed = new Utils.BooleanHolder(true);
|
||||||
applyChallenges(this.scene.gameMode, ChallengeType.POKEMON_IN_BATTLE, this, challengeAllowed);
|
applyChallenges(this.scene.gameMode, ChallengeType.POKEMON_IN_BATTLE, this, challengeAllowed);
|
||||||
return !this.isFainted() && challengeAllowed.value;
|
return !this.isFainted() && !this.wildFlee && challengeAllowed.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
isActive(onField?: boolean): boolean {
|
isActive(onField?: boolean): boolean {
|
||||||
@ -350,7 +353,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
loadAssets(ignoreOverride: boolean = true): Promise<void> {
|
loadAssets(ignoreOverride: boolean = true): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const moveIds = this.getMoveset().map(m => m.getMove().id);
|
const moveIds = this.getMoveset().map(m => m!.getMove().id); // TODO: is this bang correct?
|
||||||
Promise.allSettled(moveIds.map(m => initMoveAnim(this.scene, m)))
|
Promise.allSettled(moveIds.map(m => initMoveAnim(this.scene, m)))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
loadMoveAnimAssets(this.scene, moveIds);
|
loadMoveAnimAssets(this.scene, moveIds);
|
||||||
@ -438,7 +441,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.species.forms[this.formIndex].formKey;
|
return this.species.forms[this.formIndex].formKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFusionFormKey(): string {
|
getFusionFormKey(): string | null {
|
||||||
if (!this.fusionSpecies) {
|
if (!this.fusionSpecies) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -527,7 +530,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.summonData.fusionSpeciesForm;
|
return this.summonData.fusionSpeciesForm;
|
||||||
}
|
}
|
||||||
if (!this.fusionSpecies?.forms?.length || this.fusionFormIndex >= this.fusionSpecies?.forms.length) {
|
if (!this.fusionSpecies?.forms?.length || this.fusionFormIndex >= this.fusionSpecies?.forms.length) {
|
||||||
return this.fusionSpecies;
|
//@ts-ignore
|
||||||
|
return this.fusionSpecies; // TODO: I don't even know how to fix this... A complete cluster of classes involved + null
|
||||||
}
|
}
|
||||||
return this.fusionSpecies?.forms[this.fusionFormIndex];
|
return this.fusionSpecies?.forms[this.fusionFormIndex];
|
||||||
}
|
}
|
||||||
@ -536,7 +540,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.getAt(0) as Phaser.GameObjects.Sprite;
|
return this.getAt(0) as Phaser.GameObjects.Sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTintSprite(): Phaser.GameObjects.Sprite {
|
getTintSprite(): Phaser.GameObjects.Sprite | null {
|
||||||
return !this.maskEnabled
|
return !this.maskEnabled
|
||||||
? this.getAt(1) as Phaser.GameObjects.Sprite
|
? this.getAt(1) as Phaser.GameObjects.Sprite
|
||||||
: this.maskSprite;
|
: this.maskSprite;
|
||||||
@ -562,7 +566,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateSpritePipelineData(): void {
|
updateSpritePipelineData(): void {
|
||||||
[ this.getSprite(), this.getTintSprite() ].map(s => s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType()));
|
[ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType()));
|
||||||
this.updateInfo(true);
|
this.updateInfo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,7 +614,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
playAnim(): void {
|
playAnim(): void {
|
||||||
this.tryPlaySprite(this.getSprite(), this.getTintSprite(), this.getBattleSpriteKey());
|
this.tryPlaySprite(this.getSprite(), this.getTintSprite()!, this.getBattleSpriteKey()); // TODO: is the bag correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
getFieldPositionOffset(): [ number, number ] {
|
getFieldPositionOffset(): [ number, number ] {
|
||||||
@ -870,7 +874,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
abstract isBoss(): boolean;
|
abstract isBoss(): boolean;
|
||||||
|
|
||||||
getMoveset(ignoreOverride?: boolean): PokemonMove[] {
|
getMoveset(ignoreOverride?: boolean): (PokemonMove | null)[] {
|
||||||
const ret = !ignoreOverride && this.summonData?.moveset
|
const ret = !ignoreOverride && this.summonData?.moveset
|
||||||
? this.summonData.moveset
|
? this.summonData.moveset
|
||||||
: this.moveset;
|
: this.moveset;
|
||||||
@ -921,7 +925,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (this.metBiome === -1) {
|
if (this.metBiome === -1) {
|
||||||
levelMoves = this.getUnlockedEggMoves().concat(levelMoves);
|
levelMoves = this.getUnlockedEggMoves().concat(levelMoves);
|
||||||
}
|
}
|
||||||
return levelMoves.filter(lm => !this.moveset.some(m => m.moveId === lm));
|
return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -932,7 +936,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @returns array of {@linkcode Type}
|
* @returns array of {@linkcode Type}
|
||||||
*/
|
*/
|
||||||
getTypes(includeTeraType = false, forDefend: boolean = false, ignoreOverride?: boolean): Type[] {
|
getTypes(includeTeraType = false, forDefend: boolean = false, ignoreOverride?: boolean): Type[] {
|
||||||
const types = [];
|
const types : Type[] = [];
|
||||||
|
|
||||||
if (includeTeraType) {
|
if (includeTeraType) {
|
||||||
const teraType = this.getTeraType();
|
const teraType = this.getTeraType();
|
||||||
@ -942,7 +946,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!types.length || !includeTeraType) {
|
if (!types.length || !includeTeraType) {
|
||||||
if (!ignoreOverride && this.summonData?.types) {
|
if (!ignoreOverride && this.summonData?.types && this.summonData.types.length !== 0) {
|
||||||
this.summonData.types.forEach(t => types.push(t));
|
this.summonData.types.forEach(t => types.push(t));
|
||||||
} else {
|
} else {
|
||||||
const speciesForm = this.getSpeciesForm(ignoreOverride);
|
const speciesForm = this.getSpeciesForm(ignoreOverride);
|
||||||
@ -1077,6 +1081,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
(Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== Abilities.NONE && !this.isPlayer())) {
|
(Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== Abilities.NONE && !this.isPlayer())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Final boss does not have passive
|
||||||
|
if (this.scene.currentBattle?.battleSpec === BattleSpec.FINAL_BOSS && this instanceof EnemyPokemon) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return this.passive || this.isBoss();
|
return this.passive || this.isBoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,7 +1125,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this));
|
return (!!this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1242,7 +1252,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
? moveOrType
|
? moveOrType
|
||||||
: undefined;
|
: undefined;
|
||||||
const moveType = (moveOrType instanceof Move)
|
const moveType = (moveOrType instanceof Move)
|
||||||
? move.type
|
? move!.type // TODO: is this bang correct?
|
||||||
: moveOrType;
|
: moveOrType;
|
||||||
|
|
||||||
if (moveType === Type.STELLAR) {
|
if (moveType === Type.STELLAR) {
|
||||||
@ -1259,6 +1269,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (ignoreImmunity.value) {
|
if (ignoreImmunity.value) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[];
|
||||||
|
if (exposedTags.some(t => t.ignoreImmunity(defType, moveType))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getTypeDamageMultiplier(moveType, defType);
|
return getTypeDamageMultiplier(moveType, defType);
|
||||||
@ -1280,7 +1295,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return multiplier;
|
return multiplier as TypeDamageMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1322,7 +1337,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return (atkScore + defScore) * hpDiffRatio;
|
return (atkScore + defScore) * hpDiffRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
getEvolution(): SpeciesFormEvolution {
|
getEvolution(): SpeciesFormEvolution | null {
|
||||||
if (pokemonEvolutions.hasOwnProperty(this.species.speciesId)) {
|
if (pokemonEvolutions.hasOwnProperty(this.species.speciesId)) {
|
||||||
const evolutions = pokemonEvolutions[this.species.speciesId];
|
const evolutions = pokemonEvolutions[this.species.speciesId];
|
||||||
for (const e of evolutions) {
|
for (const e of evolutions) {
|
||||||
@ -1334,7 +1349,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isFusion() && pokemonEvolutions.hasOwnProperty(this.fusionSpecies.speciesId)) {
|
if (this.isFusion() && this.fusionSpecies && pokemonEvolutions.hasOwnProperty(this.fusionSpecies.speciesId)) {
|
||||||
const fusionEvolutions = pokemonEvolutions[this.fusionSpecies.speciesId].map(e => new FusionSpeciesFormEvolution(this.species.speciesId, e));
|
const fusionEvolutions = pokemonEvolutions[this.fusionSpecies.speciesId].map(e => new FusionSpeciesFormEvolution(this.species.speciesId, e));
|
||||||
for (const fe of fusionEvolutions) {
|
for (const fe of fusionEvolutions) {
|
||||||
if (!fe.item && this.level >= fe.level && (!fe.preFormKey || this.getFusionFormKey() === fe.preFormKey)) {
|
if (!fe.item && this.level >= fe.level && (!fe.preFormKey || this.getFusionFormKey() === fe.preFormKey)) {
|
||||||
@ -1544,7 +1559,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearFusionSpecies(): void {
|
clearFusionSpecies(): void {
|
||||||
this.fusionSpecies = undefined;
|
this.fusionSpecies = null;
|
||||||
this.fusionFormIndex = 0;
|
this.fusionFormIndex = 0;
|
||||||
this.fusionAbilityIndex = 0;
|
this.fusionAbilityIndex = 0;
|
||||||
this.fusionShiny = false;
|
this.fusionShiny = false;
|
||||||
@ -1704,9 +1719,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
// Sqrt the weight of any damaging moves with overlapping types. This is about a 0.05 - 0.1 multiplier.
|
// Sqrt the weight of any damaging moves with overlapping types. This is about a 0.05 - 0.1 multiplier.
|
||||||
// Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights double if STAB.
|
// Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights double if STAB.
|
||||||
// Status moves remain unchanged on weight, this encourages 1-2
|
// Status moves remain unchanged on weight, this encourages 1-2
|
||||||
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)).map(m => [m[0], this.moveset.some(mo => mo.getMove().category !== MoveCategory.STATUS && mo.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1]/Math.max(Math.pow(4, this.moveset.filter(mo => mo.getMove().power > 1).length)/8,0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1]]);
|
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)).map(m => [m[0], this.moveset.some(mo => mo?.getMove().category !== MoveCategory.STATUS && mo?.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1]/Math.max(Math.pow(4, this.moveset.filter(mo => (mo?.getMove().power!) > 1).length)/8,0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1]]); // TODO: is this bang correct?
|
||||||
} else { // Non-trainer pokemon just use normal weights
|
} else { // Non-trainer pokemon just use normal weights
|
||||||
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId));
|
movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId));
|
||||||
}
|
}
|
||||||
const totalWeight = movePool.reduce((v, m) => v + m[1], 0);
|
const totalWeight = movePool.reduce((v, m) => v + m[1], 0);
|
||||||
let rand = Utils.randSeedInt(totalWeight);
|
let rand = Utils.randSeedInt(totalWeight);
|
||||||
@ -1724,7 +1739,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const move = this.getMoveset().length > moveIndex
|
const move = this.getMoveset().length > moveIndex
|
||||||
? this.getMoveset()[moveIndex]
|
? this.getMoveset()[moveIndex]
|
||||||
: null;
|
: null;
|
||||||
return move?.isUsable(this, ignorePp);
|
return move?.isUsable(this, ignorePp)!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
showInfo(): void {
|
showInfo(): void {
|
||||||
@ -1773,6 +1788,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets if the pokemon has fled (implies it's a wild pokemon)
|
||||||
|
* @param status - boolean
|
||||||
|
*/
|
||||||
|
setWildFlee(status: boolean): void {
|
||||||
|
this.wildFlee = status;
|
||||||
|
}
|
||||||
|
|
||||||
updateInfo(instant?: boolean): Promise<void> {
|
updateInfo(instant?: boolean): Promise<void> {
|
||||||
return this.battleInfo.updateInfo(this, instant);
|
return this.battleInfo.updateInfo(this, instant);
|
||||||
}
|
}
|
||||||
@ -1807,7 +1830,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate);
|
this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOpponent(targetIndex: integer): Pokemon {
|
getOpponent(targetIndex: integer): Pokemon | null {
|
||||||
const ret = this.getOpponents()[targetIndex];
|
const ret = this.getOpponents()[targetIndex];
|
||||||
if (ret.summonData) {
|
if (ret.summonData) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -1865,6 +1888,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel);
|
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel);
|
||||||
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel);
|
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel);
|
||||||
|
|
||||||
|
if (target.findTag(t => t instanceof ExposedTag)) {
|
||||||
|
targetEvasionLevel.value = Math.min(0, targetEvasionLevel.value);
|
||||||
|
}
|
||||||
|
|
||||||
const accuracyMultiplier = new Utils.NumberHolder(1);
|
const accuracyMultiplier = new Utils.NumberHolder(1);
|
||||||
if (userAccuracyLevel.value !== targetEvasionLevel.value) {
|
if (userAccuracyLevel.value !== targetEvasionLevel.value) {
|
||||||
accuracyMultiplier.value = userAccuracyLevel.value > targetEvasionLevel.value
|
accuracyMultiplier.value = userAccuracyLevel.value > targetEvasionLevel.value
|
||||||
@ -1885,6 +1912,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
apply(source: Pokemon, move: Move): HitResult {
|
apply(source: Pokemon, move: Move): HitResult {
|
||||||
let result: HitResult;
|
let result: HitResult;
|
||||||
const damage = new Utils.NumberHolder(0);
|
const damage = new Utils.NumberHolder(0);
|
||||||
|
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
const defendingSidePlayField = this.isPlayer() ? this.scene.getPlayerField() : this.scene.getEnemyField();
|
const defendingSidePlayField = this.isPlayer() ? this.scene.getPlayerField() : this.scene.getEnemyField();
|
||||||
|
|
||||||
const variableCategory = new Utils.IntegerHolder(move.category);
|
const variableCategory = new Utils.IntegerHolder(move.category);
|
||||||
@ -1911,7 +1939,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// Apply arena tags for conditional protection
|
// Apply arena tags for conditional protection
|
||||||
if (!move.checkFlag(MoveFlags.IGNORE_PROTECT, source, this) && !move.isAllyTarget()) {
|
if (!move.checkFlag(MoveFlags.IGNORE_PROTECT, source, this) && !move.isAllyTarget()) {
|
||||||
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
|
||||||
this.scene.arena.applyTagsForSide(ArenaTagType.QUICK_GUARD, defendingSide, cancelled, this, move.priority);
|
this.scene.arena.applyTagsForSide(ArenaTagType.QUICK_GUARD, defendingSide, cancelled, this, move.priority);
|
||||||
this.scene.arena.applyTagsForSide(ArenaTagType.WIDE_GUARD, defendingSide, cancelled, this, move.moveTarget);
|
this.scene.arena.applyTagsForSide(ArenaTagType.WIDE_GUARD, defendingSide, cancelled, this, move.moveTarget);
|
||||||
this.scene.arena.applyTagsForSide(ArenaTagType.MAT_BLOCK, defendingSide, cancelled, this, move.category);
|
this.scene.arena.applyTagsForSide(ArenaTagType.MAT_BLOCK, defendingSide, cancelled, this, move.category);
|
||||||
@ -1968,7 +1995,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.scene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critLevel);
|
this.scene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critLevel);
|
||||||
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
|
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
|
||||||
const bonusCrit = new Utils.BooleanHolder(false);
|
const bonusCrit = new Utils.BooleanHolder(false);
|
||||||
if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) {
|
//@ts-ignore
|
||||||
|
if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
|
||||||
if (bonusCrit.value) {
|
if (bonusCrit.value) {
|
||||||
critLevel.value += 1;
|
critLevel.value += 1;
|
||||||
}
|
}
|
||||||
@ -1978,25 +2006,26 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
console.log(`crit stage: +${critLevel.value}`);
|
console.log(`crit stage: +${critLevel.value}`);
|
||||||
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))];
|
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))];
|
||||||
isCritical = !source.getTag(BattlerTagType.NO_CRIT) && (critChance === 1 || !this.scene.randBattleSeedInt(critChance));
|
isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance);
|
||||||
if (Overrides.NEVER_CRIT_OVERRIDE) {
|
if (Overrides.NEVER_CRIT_OVERRIDE) {
|
||||||
isCritical = false;
|
isCritical = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isCritical) {
|
if (isCritical) {
|
||||||
|
const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide);
|
||||||
const blockCrit = new Utils.BooleanHolder(false);
|
const blockCrit = new Utils.BooleanHolder(false);
|
||||||
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
|
applyAbAttrs(BlockCritAbAttr, this, null, blockCrit);
|
||||||
if (blockCrit.value) {
|
if (noCritTag || blockCrit.value) {
|
||||||
isCritical = false;
|
isCritical = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, null, isCritical));
|
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical));
|
||||||
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
|
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
|
||||||
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
|
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
|
||||||
applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier);
|
applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier);
|
||||||
const screenMultiplier = new Utils.NumberHolder(1);
|
const screenMultiplier = new Utils.NumberHolder(1);
|
||||||
if (!isCritical) {
|
if (!isCritical) {
|
||||||
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, move.category, this.scene.currentBattle.double, screenMultiplier);
|
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
|
||||||
}
|
}
|
||||||
const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier.value) === 0;
|
const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier.value) === 0;
|
||||||
const sourceTypes = source.getTypes();
|
const sourceTypes = source.getTypes();
|
||||||
@ -2078,6 +2107,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
isCritical = false;
|
isCritical = false;
|
||||||
result = HitResult.EFFECTIVE;
|
result = HitResult.EFFECTIVE;
|
||||||
}
|
}
|
||||||
|
result = result!; // telling TS compiler that result is defined!
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!typeMultiplier.value) {
|
if (!typeMultiplier.value) {
|
||||||
@ -2182,7 +2212,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (damage) {
|
if (damage) {
|
||||||
const attacker = this.scene.getPokemonById(source.id);
|
const attacker = this.scene.getPokemonById(source.id)!; // TODO: is this bang correct?
|
||||||
destinyTag?.lapse(attacker, BattlerTagLapseType.CUSTOM);
|
destinyTag?.lapse(attacker, BattlerTagLapseType.CUSTOM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2282,7 +2312,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
isMax(): boolean {
|
isMax(): boolean {
|
||||||
const maxForms = [SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX] as string[];
|
const maxForms = [SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX] as string[];
|
||||||
return maxForms.includes(this.getFormKey()) || maxForms.includes(this.getFusionFormKey());
|
return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!));
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
|
addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean {
|
||||||
@ -2292,7 +2322,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTag = getBattlerTag(tagType, turnCount, sourceMove, sourceId);
|
const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct?
|
||||||
|
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, newTag, cancelled);
|
applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, newTag, cancelled);
|
||||||
@ -2311,18 +2341,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @overload */
|
/** @overload */
|
||||||
getTag(tagType: BattlerTagType): BattlerTag;
|
getTag(tagType: BattlerTagType): BattlerTag | null;
|
||||||
|
|
||||||
/** @overload */
|
/** @overload */
|
||||||
getTag<T extends BattlerTag>(tagType: Constructor<T>): T;
|
getTag<T extends BattlerTag>(tagType: Constructor<T>): T | null;
|
||||||
|
|
||||||
getTag(tagType: BattlerTagType | Constructor<BattlerTag>): BattlerTag {
|
getTag(tagType: BattlerTagType | Constructor<BattlerTag>): BattlerTag | null {
|
||||||
if (!this.summonData) {
|
if (!this.summonData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return tagType instanceof Function
|
return (tagType instanceof Function
|
||||||
? this.summonData.tags.find(t => t instanceof tagType)
|
? this.summonData.tags.find(t => t instanceof tagType)
|
||||||
: this.summonData.tags.find(t => t.tagType === tagType);
|
: this.summonData.tags.find(t => t.tagType === tagType)
|
||||||
|
)!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
findTag(tagFilter: ((tag: BattlerTag) => boolean)) {
|
findTag(tagFilter: ((tag: BattlerTag) => boolean)) {
|
||||||
@ -2439,7 +2470,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.getMoveHistory().push(turnMove);
|
this.getMoveHistory().push(turnMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLastXMoves(turnCount?: integer): TurnMove[] {
|
getLastXMoves(turnCount: integer = 0): TurnMove[] {
|
||||||
const moveHistory = this.getMoveHistory();
|
const moveHistory = this.getMoveHistory();
|
||||||
return moveHistory.slice(turnCount >= 0 ? Math.max(moveHistory.length - (turnCount || 1), 0) : 0, moveHistory.length).reverse();
|
return moveHistory.slice(turnCount >= 0 ? Math.max(moveHistory.length - (turnCount || 1), 0) : 0, moveHistory.length).reverse();
|
||||||
}
|
}
|
||||||
@ -2517,9 +2548,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
let frameThreshold: number;
|
let frameThreshold: number;
|
||||||
|
|
||||||
sprite.anims.pause();
|
sprite.anims.pause();
|
||||||
tintSprite.anims.pause();
|
tintSprite?.anims.pause();
|
||||||
|
|
||||||
let faintCryTimer = this.scene.time.addEvent({
|
let faintCryTimer : Phaser.Time.TimerEvent | null = this.scene.time.addEvent({
|
||||||
delay: Utils.fixedInt(delay),
|
delay: Utils.fixedInt(delay),
|
||||||
repeat: -1,
|
repeat: -1,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
@ -2529,7 +2560,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
while (frameProgress > frameThreshold) {
|
while (frameProgress > frameThreshold) {
|
||||||
if (sprite.anims.duration) {
|
if (sprite.anims.duration) {
|
||||||
sprite.anims.nextFrame();
|
sprite.anims.nextFrame();
|
||||||
tintSprite.anims.nextFrame();
|
tintSprite?.anims.nextFrame();
|
||||||
}
|
}
|
||||||
frameProgress -= frameThreshold;
|
frameProgress -= frameThreshold;
|
||||||
}
|
}
|
||||||
@ -2537,7 +2568,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
rate *= 0.99;
|
rate *= 0.99;
|
||||||
cry.setRate(rate);
|
cry.setRate(rate);
|
||||||
} else {
|
} else {
|
||||||
faintCryTimer.destroy();
|
faintCryTimer?.destroy();
|
||||||
faintCryTimer = null;
|
faintCryTimer = null;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
@ -2596,9 +2627,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
let frameThreshold: number;
|
let frameThreshold: number;
|
||||||
|
|
||||||
sprite.anims.pause();
|
sprite.anims.pause();
|
||||||
tintSprite.anims.pause();
|
tintSprite?.anims.pause();
|
||||||
|
|
||||||
let faintCryTimer = this.scene.time.addEvent({
|
let faintCryTimer: Phaser.Time.TimerEvent | null = this.scene.time.addEvent({
|
||||||
delay: Utils.fixedInt(delay),
|
delay: Utils.fixedInt(delay),
|
||||||
repeat: -1,
|
repeat: -1,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
@ -2608,7 +2639,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
while (frameProgress > frameThreshold) {
|
while (frameProgress > frameThreshold) {
|
||||||
if (sprite.anims.duration) {
|
if (sprite.anims.duration) {
|
||||||
sprite.anims.nextFrame();
|
sprite.anims.nextFrame();
|
||||||
tintSprite.anims.nextFrame();
|
tintSprite?.anims.nextFrame();
|
||||||
}
|
}
|
||||||
frameProgress -= frameThreshold;
|
frameProgress -= frameThreshold;
|
||||||
}
|
}
|
||||||
@ -2625,7 +2656,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
fusionCry.setRate(rate);
|
fusionCry.setRate(rate);
|
||||||
}
|
}
|
||||||
if ((!cry || cry.pendingRemove) && (!fusionCry || fusionCry.pendingRemove)) {
|
if ((!cry || cry.pendingRemove) && (!fusionCry || fusionCry.pendingRemove)) {
|
||||||
faintCryTimer.destroy();
|
faintCryTimer?.destroy();
|
||||||
faintCryTimer = null;
|
faintCryTimer = null;
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
@ -2656,7 +2687,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
canSetStatus(effect: StatusEffect, quiet: boolean = false, overrideStatus: boolean = false, sourcePokemon: Pokemon = null): boolean {
|
canSetStatus(effect: StatusEffect | undefined, quiet: boolean = false, overrideStatus: boolean = false, sourcePokemon: Pokemon | null = null): boolean {
|
||||||
if (effect !== StatusEffect.FAINT) {
|
if (effect !== StatusEffect.FAINT) {
|
||||||
if (overrideStatus ? this.status?.effect === effect : this.status) {
|
if (overrideStatus ? this.status?.effect === effect : this.status) {
|
||||||
return false;
|
return false;
|
||||||
@ -2707,7 +2738,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StatusEffect.FREEZE:
|
case StatusEffect.FREEZE:
|
||||||
if (this.isOfType(Type.ICE) || [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene?.arena.weather?.weatherType)) {
|
if (this.isOfType(Type.ICE) || (this.scene?.arena?.weather?.weatherType &&[WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene.arena.weather.weatherType))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2731,7 +2762,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
trySetStatus(effect: StatusEffect, asPhase: boolean = false, sourcePokemon: Pokemon = null, cureTurn: integer = 0, sourceText: string = null): boolean {
|
trySetStatus(effect: StatusEffect | undefined, asPhase: boolean = false, sourcePokemon: Pokemon | null = null, cureTurn: integer | null = 0, sourceText: string | null = null): boolean {
|
||||||
if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) {
|
if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2745,7 +2776,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (asPhase) {
|
if (asPhase) {
|
||||||
this.scene.unshiftPhase(new ObtainStatusEffectPhase(this.scene, this.getBattlerIndex(), effect, cureTurn, sourceText, sourcePokemon));
|
this.scene.unshiftPhase(new ObtainStatusEffectPhase(this.scene, this.getBattlerIndex(), effect, cureTurn, sourceText!, sourcePokemon!)); // TODO: are these bangs correct?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2773,6 +2804,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusCureTurn = statusCureTurn!; // tell TS compiler it's defined
|
||||||
|
effect = effect!; // If `effect` is undefined then `trySetStatus()` will have already returned early via the `canSetStatus()` call
|
||||||
this.status = new Status(effect, 0, statusCureTurn?.value);
|
this.status = new Status(effect, 0, statusCureTurn?.value);
|
||||||
|
|
||||||
if (effect !== StatusEffect.FAINT) {
|
if (effect !== StatusEffect.FAINT) {
|
||||||
@ -2793,7 +2826,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
if (!revive && lastStatus === StatusEffect.FAINT) {
|
if (!revive && lastStatus === StatusEffect.FAINT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.status = undefined;
|
this.status = null;
|
||||||
if (lastStatus === StatusEffect.SLEEP) {
|
if (lastStatus === StatusEffect.SLEEP) {
|
||||||
this.setFrameRate(12);
|
this.setFrameRate(12);
|
||||||
if (this.getTag(BattlerTagType.NIGHTMARE)) {
|
if (this.getTag(BattlerTagType.NIGHTMARE)) {
|
||||||
@ -2861,16 +2894,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
setFrameRate(frameRate: integer) {
|
setFrameRate(frameRate: integer) {
|
||||||
this.scene.anims.get(this.getBattleSpriteKey()).frameRate = frameRate;
|
this.scene.anims.get(this.getBattleSpriteKey()).frameRate = frameRate;
|
||||||
this.getSprite().play(this.getBattleSpriteKey());
|
this.getSprite().play(this.getBattleSpriteKey());
|
||||||
this.getTintSprite().play(this.getBattleSpriteKey());
|
this.getTintSprite()?.play(this.getBattleSpriteKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
tint(color: number, alpha?: number, duration?: integer, ease?: string) {
|
tint(color: number, alpha?: number, duration?: integer, ease?: string) {
|
||||||
const tintSprite = this.getTintSprite();
|
const tintSprite = this.getTintSprite();
|
||||||
tintSprite.setTintFill(color);
|
tintSprite?.setTintFill(color);
|
||||||
tintSprite.setVisible(true);
|
tintSprite?.setVisible(true);
|
||||||
|
|
||||||
if (duration) {
|
if (duration) {
|
||||||
tintSprite.setAlpha(0);
|
tintSprite?.setAlpha(0);
|
||||||
|
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: tintSprite,
|
targets: tintSprite,
|
||||||
@ -2879,7 +2912,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
ease: ease || "Linear"
|
ease: ease || "Linear"
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tintSprite.setAlpha(alpha);
|
tintSprite?.setAlpha(alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2893,32 +2926,32 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
duration: duration,
|
duration: duration,
|
||||||
ease: ease || "Linear",
|
ease: ease || "Linear",
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
tintSprite.setVisible(false);
|
tintSprite?.setVisible(false);
|
||||||
tintSprite.setAlpha(1);
|
tintSprite?.setAlpha(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tintSprite.setVisible(false);
|
tintSprite?.setVisible(false);
|
||||||
tintSprite.setAlpha(1);
|
tintSprite?.setAlpha(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enableMask() {
|
enableMask() {
|
||||||
if (!this.maskEnabled) {
|
if (!this.maskEnabled) {
|
||||||
this.maskSprite = this.getTintSprite();
|
this.maskSprite = this.getTintSprite();
|
||||||
this.maskSprite.setVisible(true);
|
this.maskSprite?.setVisible(true);
|
||||||
this.maskSprite.setPosition(this.x * this.parentContainer.scale + this.parentContainer.x,
|
this.maskSprite?.setPosition(this.x * this.parentContainer.scale + this.parentContainer.x,
|
||||||
this.y * this.parentContainer.scale + this.parentContainer.y);
|
this.y * this.parentContainer.scale + this.parentContainer.y);
|
||||||
this.maskSprite.setScale(this.getSpriteScale() * this.parentContainer.scale);
|
this.maskSprite?.setScale(this.getSpriteScale() * this.parentContainer.scale);
|
||||||
this.maskEnabled = true;
|
this.maskEnabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disableMask() {
|
disableMask() {
|
||||||
if (this.maskEnabled) {
|
if (this.maskEnabled) {
|
||||||
this.maskSprite.setVisible(false);
|
this.maskSprite?.setVisible(false);
|
||||||
this.maskSprite.setPosition(0, 0);
|
this.maskSprite?.setPosition(0, 0);
|
||||||
this.maskSprite.setScale(this.getSpriteScale());
|
this.maskSprite?.setScale(this.getSpriteScale());
|
||||||
this.maskSprite = null;
|
this.maskSprite = null;
|
||||||
this.maskEnabled = false;
|
this.maskEnabled = false;
|
||||||
}
|
}
|
||||||
@ -2933,7 +2966,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
updateFusionPalette(ignoreOveride?: boolean): void {
|
updateFusionPalette(ignoreOveride?: boolean): void {
|
||||||
if (!this.getFusionSpeciesForm(ignoreOveride)) {
|
if (!this.getFusionSpeciesForm(ignoreOveride)) {
|
||||||
[ this.getSprite(), this.getTintSprite() ].map(s => {
|
[ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => {
|
||||||
s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = [];
|
s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = [];
|
||||||
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = [];
|
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = [];
|
||||||
});
|
});
|
||||||
@ -2969,9 +3002,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const frame = [ sourceFrame, sourceBackFrame, fusionFrame, fusionBackFrame ][c];
|
const frame = [ sourceFrame, sourceBackFrame, fusionFrame, fusionBackFrame ][c];
|
||||||
canv.width = frame.width;
|
canv.width = frame.width;
|
||||||
canv.height = frame.height;
|
canv.height = frame.height;
|
||||||
context.drawImage([ sourceImage, sourceBackImage, fusionImage, fusionBackImage ][c], frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height);
|
|
||||||
const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height);
|
if (context) {
|
||||||
pixelData.push(imageData.data);
|
context.drawImage([ sourceImage, sourceBackImage, fusionImage, fusionBackImage ][c], frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height);
|
||||||
|
const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height);
|
||||||
|
pixelData.push(imageData.data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let f = 0; f < 2; f++) {
|
for (let f = 0; f < 2; f++) {
|
||||||
@ -2991,7 +3027,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const color = Utils.rgbaToInt([r, g, b, a]);
|
const color = Utils.rgbaToInt([r, g, b, a]);
|
||||||
if (variantColorSet.has(color)) {
|
if (variantColorSet.has(color)) {
|
||||||
const mappedPixel = variantColorSet.get(color);
|
const mappedPixel = variantColorSet.get(color);
|
||||||
[ r, g, b, a ] = mappedPixel;
|
if (mappedPixel) {
|
||||||
|
[ r, g, b, a ] = mappedPixel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b)) {
|
if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b)) {
|
||||||
@ -3003,7 +3041,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
const fusionSpriteColors = JSON.parse(JSON.stringify(spriteColors));
|
const fusionSpriteColors = JSON.parse(JSON.stringify(spriteColors));
|
||||||
|
|
||||||
const pixelColors = [];
|
const pixelColors: number[] = [];
|
||||||
for (let f = 0; f < 2; f++) {
|
for (let f = 0; f < 2; f++) {
|
||||||
for (let i = 0; i < pixelData[f].length; i += 4) {
|
for (let i = 0; i < pixelData[f].length; i += 4) {
|
||||||
const total = pixelData[f].slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0);
|
const total = pixelData[f].slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0);
|
||||||
@ -3014,7 +3052,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fusionPixelColors = [];
|
const fusionPixelColors : number[] = [];
|
||||||
for (let f = 0; f < 2; f++) {
|
for (let f = 0; f < 2; f++) {
|
||||||
const variantColors = variantColorCache[!f ? fusionSpriteKey : fusionBackSpriteKey];
|
const variantColors = variantColorCache[!f ? fusionSpriteKey : fusionBackSpriteKey];
|
||||||
const variantColorSet = new Map<integer, integer[]>();
|
const variantColorSet = new Map<integer, integer[]>();
|
||||||
@ -3033,7 +3071,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const color = Utils.rgbaToInt([r, g, b, a]);
|
const color = Utils.rgbaToInt([r, g, b, a]);
|
||||||
if (variantColorSet.has(color)) {
|
if (variantColorSet.has(color)) {
|
||||||
const mappedPixel = variantColorSet.get(color);
|
const mappedPixel = variantColorSet.get(color);
|
||||||
[ r, g, b, a ] = mappedPixel;
|
if (mappedPixel) {
|
||||||
|
[ r, g, b, a ] = mappedPixel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fusionPixelColors.push(argbFromRgba({ r, g, b, a }));
|
fusionPixelColors.push(argbFromRgba({ r, g, b, a }));
|
||||||
@ -3053,9 +3093,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
Math.random = originalRandom;
|
Math.random = originalRandom;
|
||||||
|
|
||||||
|
paletteColors = paletteColors!; // tell TS compiler that paletteColors is defined!
|
||||||
|
fusionPaletteColors = fusionPaletteColors!; // TS compiler that fusionPaletteColors is defined!
|
||||||
const [ palette, fusionPalette ] = [ paletteColors, fusionPaletteColors ]
|
const [ palette, fusionPalette ] = [ paletteColors, fusionPaletteColors ]
|
||||||
.map(paletteColors => {
|
.map(paletteColors => {
|
||||||
let keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a) < paletteColors.get(b) ? 1 : -1);
|
let keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a)! < paletteColors.get(b)! ? 1 : -1);
|
||||||
let rgbaColors: Map<number, integer[]>;
|
let rgbaColors: Map<number, integer[]>;
|
||||||
let hsvColors: Map<number, number[]>;
|
let hsvColors: Map<number, number[]>;
|
||||||
|
|
||||||
@ -3068,19 +3110,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
map.set(k, Object.values(rgbaFromArgb(k))); return map;
|
map.set(k, Object.values(rgbaFromArgb(k))); return map;
|
||||||
}, new Map<number, integer[]>());
|
}, new Map<number, integer[]>());
|
||||||
hsvColors = Array.from(rgbaColors.keys()).reduce((map: Map<number, number[]>, k: number) => {
|
hsvColors = Array.from(rgbaColors.keys()).reduce((map: Map<number, number[]>, k: number) => {
|
||||||
const rgb = rgbaColors.get(k).slice(0, 3);
|
const rgb = rgbaColors.get(k)!.slice(0, 3);
|
||||||
map.set(k, Utils.rgbToHsv(rgb[0], rgb[1], rgb[2]));
|
map.set(k, Utils.rgbToHsv(rgb[0], rgb[1], rgb[2]));
|
||||||
return map;
|
return map;
|
||||||
}, new Map<number, number[]>());
|
}, new Map<number, number[]>());
|
||||||
|
|
||||||
for (let c = keys.length - 1; c >= 0; c--) {
|
for (let c = keys.length - 1; c >= 0; c--) {
|
||||||
const hsv = hsvColors.get(keys[c]);
|
const hsv = hsvColors.get(keys[c])!;
|
||||||
for (let c2 = 0; c2 < c; c2++) {
|
for (let c2 = 0; c2 < c; c2++) {
|
||||||
const hsv2 = hsvColors.get(keys[c2]);
|
const hsv2 = hsvColors.get(keys[c2])!;
|
||||||
const diff = Math.abs(hsv[0] - hsv2[0]);
|
const diff = Math.abs(hsv[0] - hsv2[0]);
|
||||||
if (diff < 30 || diff >= 330) {
|
if (diff < 30 || diff >= 330) {
|
||||||
if (mappedColors.has(keys[c])) {
|
if (mappedColors.has(keys[c])) {
|
||||||
mappedColors.get(keys[c]).push(keys[c2]);
|
mappedColors.get(keys[c])!.push(keys[c2]);
|
||||||
} else {
|
} else {
|
||||||
mappedColors.set(keys[c], [ keys[c2] ]);
|
mappedColors.set(keys[c], [ keys[c2] ]);
|
||||||
}
|
}
|
||||||
@ -3090,10 +3132,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mappedColors.forEach((values: integer[], key: integer) => {
|
mappedColors.forEach((values: integer[], key: integer) => {
|
||||||
const keyColor = rgbaColors.get(key);
|
const keyColor = rgbaColors.get(key)!;
|
||||||
const valueColors = values.map(v => rgbaColors.get(v));
|
const valueColors = values.map(v => rgbaColors.get(v)!);
|
||||||
const color = keyColor.slice(0);
|
const color = keyColor.slice(0);
|
||||||
let count = paletteColors.get(key);
|
let count = paletteColors.get(key)!;
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
const valueCount = paletteColors.get(value);
|
const valueCount = paletteColors.get(value);
|
||||||
if (!valueCount) {
|
if (!valueCount) {
|
||||||
@ -3103,10 +3145,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let c = 0; c < 3; c++) {
|
for (let c = 0; c < 3; c++) {
|
||||||
color[c] *= (paletteColors.get(key) / count);
|
color[c] *= (paletteColors.get(key)! / count);
|
||||||
values.forEach((value: integer, i: integer) => {
|
values.forEach((value: integer, i: integer) => {
|
||||||
if (paletteColors.has(value)) {
|
if (paletteColors.has(value)) {
|
||||||
const valueCount = paletteColors.get(value);
|
const valueCount = paletteColors.get(value)!;
|
||||||
color[c] += valueColors[i][c] * (valueCount / count);
|
color[c] += valueColors[i][c] * (valueCount / count);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -3124,7 +3166,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
paletteColors.set(argbFromRgba({ r: color[0], g: color[1], b: color[2], a: color[3] }), count);
|
paletteColors.set(argbFromRgba({ r: color[0], g: color[1], b: color[2], a: color[3] }), count);
|
||||||
});
|
});
|
||||||
|
|
||||||
keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a) < paletteColors.get(b) ? 1 : -1);
|
keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a)! < paletteColors.get(b)! ? 1 : -1);
|
||||||
} while (mappedColors.size);
|
} while (mappedColors.size);
|
||||||
|
|
||||||
return keys.map(c => Object.values(rgbaFromArgb(c)));
|
return keys.map(c => Object.values(rgbaFromArgb(c)));
|
||||||
@ -3155,7 +3197,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ this.getSprite(), this.getTintSprite() ].map(s => {
|
[ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => {
|
||||||
s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = spriteColors;
|
s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = spriteColors;
|
||||||
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = fusionSpriteColors;
|
s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = fusionSpriteColors;
|
||||||
});
|
});
|
||||||
@ -3219,7 +3261,7 @@ export default interface Pokemon {
|
|||||||
export class PlayerPokemon extends Pokemon {
|
export class PlayerPokemon extends Pokemon {
|
||||||
public compatibleTms: Moves[];
|
public compatibleTms: Moves[];
|
||||||
|
|
||||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender: Gender, shiny: boolean, variant: Variant, ivs: integer[], nature: Nature, dataSource: Pokemon | PokemonData) {
|
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) {
|
||||||
super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
|
||||||
|
|
||||||
if (Overrides.STATUS_OVERRIDE) {
|
if (Overrides.STATUS_OVERRIDE) {
|
||||||
@ -3235,7 +3277,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dataSource) {
|
if (!dataSource) {
|
||||||
this.generateAndPopulateMoveset();
|
this.moveset = [];
|
||||||
}
|
}
|
||||||
this.generateCompatibleTms();
|
this.generateCompatibleTms();
|
||||||
}
|
}
|
||||||
@ -3323,11 +3365,11 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
|
|
||||||
addFriendship(friendship: integer): void {
|
addFriendship(friendship: integer): void {
|
||||||
const starterSpeciesId = this.species.getRootSpeciesId();
|
const starterSpeciesId = this.species.getRootSpeciesId();
|
||||||
const fusionStarterSpeciesId = this.isFusion() ? this.fusionSpecies.getRootSpeciesId() : 0;
|
const fusionStarterSpeciesId = this.isFusion() && this.fusionSpecies ? this.fusionSpecies.getRootSpeciesId() : 0;
|
||||||
const starterData = [
|
const starterData = [
|
||||||
this.scene.gameData.starterData[starterSpeciesId],
|
this.scene.gameData.starterData[starterSpeciesId],
|
||||||
fusionStarterSpeciesId ? this.scene.gameData.starterData[fusionStarterSpeciesId] : null
|
fusionStarterSpeciesId ? this.scene.gameData.starterData[fusionStarterSpeciesId] : null
|
||||||
].filter(d => d);
|
].filter(d => !!d);
|
||||||
const amount = new Utils.IntegerHolder(friendship);
|
const amount = new Utils.IntegerHolder(friendship);
|
||||||
const starterAmount = new Utils.IntegerHolder(Math.floor(friendship * (this.scene.gameMode.isClassic && friendship > 0 ? 2 : 1) / (fusionStarterSpeciesId ? 2 : 1)));
|
const starterAmount = new Utils.IntegerHolder(Math.floor(friendship * (this.scene.gameMode.isClassic && friendship > 0 ? 2 : 1) / (fusionStarterSpeciesId ? 2 : 1)));
|
||||||
if (amount.value > 0) {
|
if (amount.value > 0) {
|
||||||
@ -3391,7 +3433,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPossibleEvolution(evolution: SpeciesFormEvolution): Promise<Pokemon> {
|
getPossibleEvolution(evolution: SpeciesFormEvolution | null): Promise<Pokemon> {
|
||||||
|
if (!evolution) {
|
||||||
|
return new Promise(resolve => resolve(this));
|
||||||
|
}
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const evolutionSpecies = getPokemonSpecies(evolution.speciesId);
|
const evolutionSpecies = getPokemonSpecies(evolution.speciesId);
|
||||||
const isFusion = evolution instanceof FusionSpeciesFormEvolution;
|
const isFusion = evolution instanceof FusionSpeciesFormEvolution;
|
||||||
@ -3412,7 +3457,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
evolve(evolution: SpeciesFormEvolution, preEvolution: PokemonSpeciesForm): Promise<void> {
|
evolve(evolution: SpeciesFormEvolution | null, preEvolution: PokemonSpeciesForm): Promise<void> {
|
||||||
|
if (!evolution) {
|
||||||
|
return new Promise(resolve => resolve());
|
||||||
|
}
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.pauseEvolutions = false;
|
this.pauseEvolutions = false;
|
||||||
// Handles Nincada evolving into Ninjask + Shedinja
|
// Handles Nincada evolving into Ninjask + Shedinja
|
||||||
@ -3424,7 +3472,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.fusionSpecies = getPokemonSpecies(evolution.speciesId);
|
this.fusionSpecies = getPokemonSpecies(evolution.speciesId);
|
||||||
}
|
}
|
||||||
if (evolution.preFormKey !== null) {
|
if (evolution.preFormKey !== null) {
|
||||||
const formIndex = Math.max((!isFusion ? this.species : this.fusionSpecies).forms.findIndex(f => f.formKey === evolution.evoFormKey), 0);
|
const formIndex = Math.max((!isFusion || !this.fusionSpecies ? this.species : this.fusionSpecies).forms.findIndex(f => f.formKey === evolution.evoFormKey), 0);
|
||||||
if (!isFusion) {
|
if (!isFusion) {
|
||||||
this.formIndex = formIndex;
|
this.formIndex = formIndex;
|
||||||
} else {
|
} else {
|
||||||
@ -3480,10 +3528,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
const isFusion = evolution instanceof FusionSpeciesFormEvolution;
|
const isFusion = evolution instanceof FusionSpeciesFormEvolution;
|
||||||
|
|
||||||
const evoSpecies = (!isFusion ? this.species : this.fusionSpecies);
|
const evoSpecies = (!isFusion ? this.species : this.fusionSpecies);
|
||||||
if (evoSpecies.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) {
|
if (evoSpecies?.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) {
|
||||||
const newEvolution = pokemonEvolutions[evoSpecies.speciesId][1];
|
const newEvolution = pokemonEvolutions[evoSpecies.speciesId][1];
|
||||||
|
|
||||||
if (newEvolution.condition.predicate(this)) {
|
if (newEvolution.condition?.predicate(this)) {
|
||||||
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature);
|
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature);
|
||||||
newPokemon.natureOverride = this.natureOverride;
|
newPokemon.natureOverride = this.natureOverride;
|
||||||
newPokemon.passive = this.passive;
|
newPokemon.passive = this.passive;
|
||||||
@ -3579,7 +3627,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
if (!this.isFainted()) {
|
if (!this.isFainted()) {
|
||||||
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
|
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
|
||||||
this.hp = Math.min(this.hp, this.stats[Stat.HP]);
|
this.hp = Math.min(this.hp, this.stats[Stat.HP]);
|
||||||
this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two
|
this.status = getRandomStatus(this.status!, pokemon.status!); // Get a random valid status between the two // TODO: are the bangs correct?
|
||||||
} else if (!pokemon.isFainted()) {
|
} else if (!pokemon.isFainted()) {
|
||||||
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
|
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
|
||||||
this.hp = Math.max(this.hp, 1);
|
this.hp = Math.max(this.hp, 1);
|
||||||
@ -3604,7 +3652,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.scene.removePartyMemberModifiers(fusedPartyMemberIndex);
|
this.scene.removePartyMemberModifiers(fusedPartyMemberIndex);
|
||||||
this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0];
|
this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0];
|
||||||
const newPartyMemberIndex = this.scene.getParty().indexOf(this);
|
const newPartyMemberIndex = this.scene.getParty().indexOf(this);
|
||||||
pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, newPartyMemberIndex, m.getMove().id)));
|
pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, newPartyMemberIndex, m!.getMove().id))); // TODO: is the bang correct?
|
||||||
pokemon.destroy();
|
pokemon.destroy();
|
||||||
this.updateFusionPalette();
|
this.updateFusionPalette();
|
||||||
resolve();
|
resolve();
|
||||||
@ -3624,9 +3672,9 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
|
|
||||||
/** Returns a deep copy of this Pokemon's moveset array */
|
/** Returns a deep copy of this Pokemon's moveset array */
|
||||||
copyMoveset(): PokemonMove[] {
|
copyMoveset(): PokemonMove[] {
|
||||||
const newMoveset = [];
|
const newMoveset : PokemonMove[] = [];
|
||||||
this.moveset.forEach(move =>
|
this.moveset.forEach(move =>
|
||||||
newMoveset.push(new PokemonMove(move.moveId, 0, move.ppUp, move.virtual)));
|
newMoveset.push(new PokemonMove(move!.moveId, 0, move!.ppUp, move!.virtual))); // TODO: are those bangs correct?
|
||||||
|
|
||||||
return newMoveset;
|
return newMoveset;
|
||||||
}
|
}
|
||||||
@ -3640,9 +3688,9 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
/** To indicate of the instance was populated with a dataSource -> e.g. loaded & populated from session data */
|
/** To indicate of the instance was populated with a dataSource -> e.g. loaded & populated from session data */
|
||||||
public readonly isPopulatedFromDataSource: boolean;
|
public readonly isPopulatedFromDataSource: boolean;
|
||||||
|
|
||||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean, dataSource: PokemonData) {
|
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean, dataSource?: PokemonData) {
|
||||||
super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource?.formIndex,
|
super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource?.formIndex,
|
||||||
dataSource?.gender, dataSource ? dataSource.shiny : false, dataSource ? dataSource.variant : undefined, null, dataSource ? dataSource.nature : undefined, dataSource);
|
dataSource?.gender, dataSource ? dataSource.shiny : false, dataSource ? dataSource.variant : undefined, undefined, dataSource ? dataSource.nature : undefined, dataSource);
|
||||||
|
|
||||||
this.trainerSlot = trainerSlot;
|
this.trainerSlot = trainerSlot;
|
||||||
this.isPopulatedFromDataSource = !!dataSource; // if a dataSource is provided, then it was populated from dataSource
|
this.isPopulatedFromDataSource = !!dataSource; // if a dataSource is provided, then it was populated from dataSource
|
||||||
@ -3675,7 +3723,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
let speciesId = species.speciesId;
|
let speciesId = species.speciesId;
|
||||||
while ((prevolution = pokemonPrevolutions[speciesId])) {
|
while ((prevolution = pokemonPrevolutions[speciesId])) {
|
||||||
const evolution = pokemonEvolutions[prevolution].find(pe => pe.speciesId === speciesId && (!pe.evoFormKey || pe.evoFormKey === this.getFormKey()));
|
const evolution = pokemonEvolutions[prevolution].find(pe => pe.speciesId === speciesId && (!pe.evoFormKey || pe.evoFormKey === this.getFormKey()));
|
||||||
if (evolution.condition?.enforceFunc) {
|
if (evolution?.condition?.enforceFunc) {
|
||||||
evolution.condition.enforceFunc(this);
|
evolution.condition.enforceFunc(this);
|
||||||
}
|
}
|
||||||
speciesId = prevolution;
|
speciesId = prevolution;
|
||||||
@ -3751,7 +3799,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
getNextMove(): QueuedMove {
|
getNextMove(): QueuedMove {
|
||||||
// If this Pokemon has a move already queued, return it.
|
// If this Pokemon has a move already queued, return it.
|
||||||
const queuedMove = this.getMoveQueue().length
|
const queuedMove = this.getMoveQueue().length
|
||||||
? this.getMoveset().find(m => m.moveId === this.getMoveQueue()[0].move)
|
? this.getMoveset().find(m => m?.moveId === this.getMoveQueue()[0].move)
|
||||||
: null;
|
: null;
|
||||||
if (queuedMove) {
|
if (queuedMove) {
|
||||||
if (queuedMove.isUsable(this, this.getMoveQueue()[0].ignorePP)) {
|
if (queuedMove.isUsable(this, this.getMoveQueue()[0].ignorePP)) {
|
||||||
@ -3763,24 +3811,24 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter out any moves this Pokemon cannot use
|
// Filter out any moves this Pokemon cannot use
|
||||||
const movePool = this.getMoveset().filter(m => m.isUsable(this));
|
const movePool = this.getMoveset().filter(m => m?.isUsable(this));
|
||||||
// If no moves are left, use Struggle. Otherwise, continue with move selection
|
// If no moves are left, use Struggle. Otherwise, continue with move selection
|
||||||
if (movePool.length) {
|
if (movePool.length) {
|
||||||
// If there's only 1 move in the move pool, use it.
|
// If there's only 1 move in the move pool, use it.
|
||||||
if (movePool.length === 1) {
|
if (movePool.length === 1) {
|
||||||
return { move: movePool[0].moveId, targets: this.getNextTargets(movePool[0].moveId) };
|
return { move: movePool[0]!.moveId, targets: this.getNextTargets(movePool[0]!.moveId) }; // TODO: are the bangs correct?
|
||||||
}
|
}
|
||||||
// If a move is forced because of Encore, use it.
|
// If a move is forced because of Encore, use it.
|
||||||
const encoreTag = this.getTag(EncoreTag) as EncoreTag;
|
const encoreTag = this.getTag(EncoreTag) as EncoreTag;
|
||||||
if (encoreTag) {
|
if (encoreTag) {
|
||||||
const encoreMove = movePool.find(m => m.moveId === encoreTag.moveId);
|
const encoreMove = movePool.find(m => m?.moveId === encoreTag.moveId);
|
||||||
if (encoreMove) {
|
if (encoreMove) {
|
||||||
return { move: encoreMove.moveId, targets: this.getNextTargets(encoreMove.moveId) };
|
return { move: encoreMove.moveId, targets: this.getNextTargets(encoreMove.moveId) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (this.aiType) {
|
switch (this.aiType) {
|
||||||
case AiType.RANDOM: // No enemy should spawn with this AI type in-game
|
case AiType.RANDOM: // No enemy should spawn with this AI type in-game
|
||||||
const moveId = movePool[this.scene.randBattleSeedInt(movePool.length)].moveId;
|
const moveId = movePool[this.scene.randBattleSeedInt(movePool.length)]!.moveId; // TODO: is the bang correct?
|
||||||
return { move: moveId, targets: this.getNextTargets(moveId) };
|
return { move: moveId, targets: this.getNextTargets(moveId) };
|
||||||
case AiType.SMART_RANDOM:
|
case AiType.SMART_RANDOM:
|
||||||
case AiType.SMART:
|
case AiType.SMART:
|
||||||
@ -3790,9 +3838,9 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
* For more information on how benefit scores are calculated, see `docs/enemy-ai.md`.
|
* For more information on how benefit scores are calculated, see `docs/enemy-ai.md`.
|
||||||
*/
|
*/
|
||||||
const moveScores = movePool.map(() => 0);
|
const moveScores = movePool.map(() => 0);
|
||||||
const moveTargets = Object.fromEntries(movePool.map(m => [ m.moveId, this.getNextTargets(m.moveId) ]));
|
const moveTargets = Object.fromEntries(movePool.map(m => [ m!.moveId, this.getNextTargets(m!.moveId) ])); // TODO: are those bangs correct?
|
||||||
for (const m in movePool) {
|
for (const m in movePool) {
|
||||||
const pokemonMove = movePool[m];
|
const pokemonMove = movePool[m]!; // TODO: is the bang correct?
|
||||||
const move = pokemonMove.getMove();
|
const move = pokemonMove.getMove();
|
||||||
|
|
||||||
let moveScore = moveScores[m];
|
let moveScore = moveScores[m];
|
||||||
@ -3873,8 +3921,8 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName()));
|
console.log(movePool.map(m => m!.getName()), moveScores, r, sortedMovePool.map(m => m!.getName())); // TODO: are those bangs correct?
|
||||||
return { move: sortedMovePool[r].moveId, targets: moveTargets[sortedMovePool[r].moveId] };
|
return { move: sortedMovePool[r]!.moveId, targets: moveTargets[sortedMovePool[r]!.moveId] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3937,7 +3985,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const thresholds: integer[] = [];
|
const thresholds: integer[] = [];
|
||||||
let totalWeight: integer;
|
let totalWeight: integer = 0;
|
||||||
targetWeights.reduce((total: integer, w: integer) => {
|
targetWeights.reduce((total: integer, w: integer) => {
|
||||||
total += w;
|
total += w;
|
||||||
thresholds.push(total);
|
thresholds.push(total);
|
||||||
@ -3951,7 +3999,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
* is greater than that random number.
|
* is greater than that random number.
|
||||||
*/
|
*/
|
||||||
const randValue = this.scene.randBattleSeedInt(totalWeight);
|
const randValue = this.scene.randBattleSeedInt(totalWeight);
|
||||||
let targetIndex: integer;
|
let targetIndex: integer = 0;
|
||||||
|
|
||||||
thresholds.every((t, i) => {
|
thresholds.every((t, i) => {
|
||||||
if (randValue >= t) {
|
if (randValue >= t) {
|
||||||
@ -4127,7 +4175,7 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
|
|
||||||
addToParty(pokeballType: PokeballType) {
|
addToParty(pokeballType: PokeballType) {
|
||||||
const party = this.scene.getParty();
|
const party = this.scene.getParty();
|
||||||
let ret: PlayerPokemon = null;
|
let ret: PlayerPokemon | null = null;
|
||||||
|
|
||||||
if (party.length < 6) {
|
if (party.length < 6) {
|
||||||
this.pokeball = pokeballType;
|
this.pokeball = pokeballType;
|
||||||
@ -4174,15 +4222,15 @@ export class PokemonSummonData {
|
|||||||
public abilitySuppressed: boolean = false;
|
public abilitySuppressed: boolean = false;
|
||||||
public abilitiesApplied: Abilities[] = [];
|
public abilitiesApplied: Abilities[] = [];
|
||||||
|
|
||||||
public speciesForm: PokemonSpeciesForm;
|
public speciesForm: PokemonSpeciesForm | null;
|
||||||
public fusionSpeciesForm: PokemonSpeciesForm;
|
public fusionSpeciesForm: PokemonSpeciesForm;
|
||||||
public ability: Abilities = Abilities.NONE;
|
public ability: Abilities = Abilities.NONE;
|
||||||
public gender: Gender;
|
public gender: Gender;
|
||||||
public fusionGender: Gender;
|
public fusionGender: Gender;
|
||||||
public stats: integer[];
|
public stats: integer[];
|
||||||
public moveset: PokemonMove[];
|
public moveset: (PokemonMove | null)[];
|
||||||
// If not initialized this value will not be populated from save data.
|
// If not initialized this value will not be populated from save data.
|
||||||
public types: Type[] = null;
|
public types: Type[] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PokemonBattleData {
|
export class PokemonBattleData {
|
||||||
|
@ -121,7 +121,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
// Determine the title to include based on the configuration and includeTitle flag.
|
// Determine the title to include based on the configuration and includeTitle flag.
|
||||||
let title = includeTitle && this.config.title ? this.config.title : null;
|
let title = includeTitle && this.config.title ? this.config.title : null;
|
||||||
const evilTeamTitles = ["grunt", "admin", "sage"];
|
const evilTeamTitles = ["grunt"];
|
||||||
if (this.name === "" && evilTeamTitles.some(t => name.toLocaleLowerCase().includes(t))) {
|
if (this.name === "" && evilTeamTitles.some(t => name.toLocaleLowerCase().includes(t))) {
|
||||||
// This is a evil team grunt so we localize it by only using the "name" as the title
|
// This is a evil team grunt so we localize it by only using the "name" as the title
|
||||||
title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`);
|
title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`);
|
||||||
@ -165,6 +165,8 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
name = i18next.t(`trainerNames:${this.config.nameDouble.toLowerCase().replace(/\s/g, "_")}`);
|
name = i18next.t(`trainerNames:${this.config.nameDouble.toLowerCase().replace(/\s/g, "_")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(title ? `${title} ${name}` : name);
|
||||||
|
|
||||||
// Return the formatted name, including the title if it is set.
|
// Return the formatted name, including the title if it is set.
|
||||||
return title ? `${title} ${name}` : name;
|
return title ? `${title} ${name}` : name;
|
||||||
}
|
}
|
||||||
@ -206,7 +208,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPartyLevels(waveIndex: integer): integer[] {
|
getPartyLevels(waveIndex: integer): integer[] {
|
||||||
const ret = [];
|
const ret: number[] = [];
|
||||||
const partyTemplate = this.getPartyTemplate();
|
const partyTemplate = this.getPartyTemplate();
|
||||||
|
|
||||||
const difficultyWaveIndex = this.scene.gameMode.getWaveForDifficulty(waveIndex);
|
const difficultyWaveIndex = this.scene.gameMode.getWaveForDifficulty(waveIndex);
|
||||||
@ -255,7 +257,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
genPartyMember(index: integer): EnemyPokemon {
|
genPartyMember(index: integer): EnemyPokemon {
|
||||||
const battle = this.scene.currentBattle;
|
const battle = this.scene.currentBattle;
|
||||||
const level = battle.enemyLevels[index];
|
const level = battle.enemyLevels?.[index]!; // TODO: is this bang correct?
|
||||||
|
|
||||||
let ret: EnemyPokemon;
|
let ret: EnemyPokemon;
|
||||||
|
|
||||||
@ -288,7 +290,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create an empty species pool (which will be set to one of the species pools based on the index)
|
// Create an empty species pool (which will be set to one of the species pools based on the index)
|
||||||
let newSpeciesPool = [];
|
let newSpeciesPool: Species[] = [];
|
||||||
let useNewSpeciesPool = false;
|
let useNewSpeciesPool = false;
|
||||||
|
|
||||||
// If we are in a double battle of named trainers, we need to use alternate species pools (generate half the party from each trainer)
|
// If we are in a double battle of named trainers, we need to use alternate species pools (generate half the party from each trainer)
|
||||||
@ -313,7 +315,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
return !species.some(s => AlreadyUsedSpecies.includes(s));
|
return !species.some(s => AlreadyUsedSpecies.includes(s));
|
||||||
}
|
}
|
||||||
return !AlreadyUsedSpecies.includes(species);
|
return !AlreadyUsedSpecies.includes(species);
|
||||||
});
|
}).flat();
|
||||||
|
|
||||||
// Filter out the species that are already in the enemy party from the partner trainer species pool
|
// Filter out the species that are already in the enemy party from the partner trainer species pool
|
||||||
const speciesPoolPartnerFiltered = speciesPoolPartner.filter(species => {
|
const speciesPoolPartnerFiltered = speciesPoolPartner.filter(species => {
|
||||||
@ -322,7 +324,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
return !species.some(s => AlreadyUsedSpecies.includes(s));
|
return !species.some(s => AlreadyUsedSpecies.includes(s));
|
||||||
}
|
}
|
||||||
return !AlreadyUsedSpecies.includes(species);
|
return !AlreadyUsedSpecies.includes(species);
|
||||||
});
|
}).flat();
|
||||||
|
|
||||||
|
|
||||||
// If the index is even, use the species pool for the main trainer (that way he only uses his own pokemon in battle)
|
// If the index is even, use the species pool for the main trainer (that way he only uses his own pokemon in battle)
|
||||||
@ -368,7 +370,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
|
||||||
}, this.config.hasStaticParty ? this.config.getDerivedType() + ((index + 1) << 8) : this.scene.currentBattle.waveIndex + (this.config.getDerivedType() << 10) + (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8));
|
}, this.config.hasStaticParty ? this.config.getDerivedType() + ((index + 1) << 8) : this.scene.currentBattle.waveIndex + (this.config.getDerivedType() << 10) + (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8));
|
||||||
|
|
||||||
return ret;
|
return ret!; // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -479,7 +481,7 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
if (maxScorePartyMemberIndexes.length > 1) {
|
if (maxScorePartyMemberIndexes.length > 1) {
|
||||||
let rand: integer;
|
let rand: integer;
|
||||||
this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length), this.scene.currentBattle.turn << 2);
|
this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length), this.scene.currentBattle.turn << 2);
|
||||||
return maxScorePartyMemberIndexes[rand];
|
return maxScorePartyMemberIndexes[rand!];
|
||||||
}
|
}
|
||||||
|
|
||||||
return maxScorePartyMemberIndexes[0];
|
return maxScorePartyMemberIndexes[0];
|
||||||
@ -497,6 +499,9 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
return 0.45;
|
return 0.45;
|
||||||
case PartyMemberStrength.STRONGER:
|
case PartyMemberStrength.STRONGER:
|
||||||
return 0.375;
|
return 0.375;
|
||||||
|
default:
|
||||||
|
console.warn("getPartyMemberModifierChanceMultiplier not defined. Using default 0");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|