Compare commits

...

20 Commits

Author SHA1 Message Date
AJ Fontaine e5426b9446
Merge ec7eeea2a4 into 6030b780f2 2024-09-17 20:07:27 -07:00
flx-sta 6030b780f2
[Move][Mirror] Update HitTagAttr attributes v2 (#4297)
* [Move] Updated HitAttr tags

Affects Whirlwind/Fly, Steamroller/Minimize, and Malicious Moonsault/Minimize

* [Move] Update for MinimizeAccuracyAttr

Affects Steamroller and Malicious Moonsault

* add: whirlwind test

* add: steamroller test

* rename: `AlwaysHitMinimizeAttr` (from `MinimizeAccuracyAttr`)

* rename: `DealsDoubleDamageToTagAttr` (from `HitsTagAttr`)

---------

Co-authored-by: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com>
2024-09-17 22:41:46 -04:00
Jannik Tappert e386504977
[BUG][Beta] Fix English Status Symbols (#4293)
* Have English Status Symbols show up again :)

* It now uses the function instead

---------

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
2024-09-17 22:26:47 -04:00
podar 106ed6b27b
[Bug] Using default animation for errors that occur. (#4266)
* Using default animation for errors that occur.

* Renaming function to make it clear that logging happens

* Updating logging for missing animations

* Missed committing linter changes

* Update src/data/battle-anims.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/data/battle-anims.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update src/data/battle-anims.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
2024-09-17 22:15:47 -04:00
flx-sta 4389bff5d0
[Bug] Fix stat-protection-attribute not taking inverts (e.g. Contrary) into account (#4031)
* add generic types to`Pokemon.getAbilityAttrs()`

* add invert check to `ProtectStatAbAttr.apply...`

This makes sure that a stat is only protected if no other ability inverts the change. E.g. `Contrary` inverts any decrease to an increase

* migrate contrary.test.ts to game.classicMode

* move `StatStageChangeMultiplierAbAttr` resolve above `ProtectStatAbAttr`

The effect of StatStageChangeMultiplierAbAttr is now applied before resolving any ProtectStatAbAttr. Thus the stage (level) of the BattleStat change was properly altered at the time of resolving the protection

* revert ability.ts changes

* add automated tests for `Clear Body` + `Contrary`

* StateStageChangePhase replace ~~`IntegerHolder`~~ with `NumberHolder`

Update Utils import and replace all occurcences of `Utils.`

* contrary.test.ts: remove `js` import
2024-09-17 19:14:41 -07:00
Madmadness65 00ba2eebc8
Add new biome BGM by Firel (#4301) 2024-09-17 21:57:34 +01:00
Leo Kim fe69bd2b55
add missing translation for korean (#4295) 2024-09-17 10:50:51 -07:00
Dakurei 1fb5389765
Auto center the window vertically (#2686)
+ When the game is played in landscape format
    or in portrait format when it's not a touchscreen
2024-09-17 17:55:50 +01:00
cam 18dc9d216c
[Bug][Move] Clanging Scales animation on incorrect sprite (#4290)
Set focus to 1 on move's target sprite for every frame.
2024-09-17 15:58:49 +01:00
AJ Fontaine 3ed2c74f38
[Enhancement] Add Met Wave to Pokemon Data (#4271)
Co-authored-by: Lugiad <adrien.grivel@hotmail.fr>
Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com>
Co-authored-by: Chapybara-jp <charlie.beer@hotmail.com>
2024-09-16 15:44:03 -07:00
PigeonBar 009fd3fc5c
[Bug] Fix reloads erasing weather on first wave of biome (#4078)
* [Bug] Fix reloads erasing weather on first wave of biome

* Minor revisions

* Minor revisions 2

* Update test

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-09-16 15:30:42 -04:00
MokaStitcher 128df1b6d2
[QoL] [ui] Make tutorials darken background (#4283)
* [ui] add prompt icon to the message boxes that don't have it

* [ui] add background overlay during tutorials

* add missing doc

* Improve documentation based on suggestions

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-09-16 15:19:34 -04:00
Jannik Tappert 4605ed4c4f
[Localization] Localized status condition icon (#4286)
* Status Condition Icons now can be localized. Already added german

* More
2024-09-16 15:18:57 -04:00
podar 0dabf87815
Being explicit in vite configuration for relative paths (#4264) 2024-09-16 21:08:50 +02:00
Blitzy d5cce666d3
Remove Dragon Ascent Requirement (#4284) 2024-09-16 20:03:13 +01:00
Tomás Marques 2221afca81
[QoL] Slight Resize and Reallocate to IV graph in new game screen (#1928)
* Resize and Reallocate to IV graph in new game

* decrease moveset container size

* fix to font shadow

* fix to shadows

* Remove unused variable

* Revert IV text back to original size

* fix eslint error check post merge

* Update src/ui/stats-container.ts

Reformat statLabel line.

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: tomasrggm <tomasrggm@gmail.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-09-16 11:44:11 -07:00
Tempoanon 72439ffff7
[Move][Beta] Add back grounded condition to ground shaky moves and grassy terrain (#4276) 2024-09-16 10:58:28 -04:00
Lugiad 6c2880dc30
[Localization] Missing French entries (#4270)
* Update battle.json

* Update move-trigger.json

* Update party-ui-handler.json

* Update tutorial.json

* Update tutorial.json

* Update trainer-names.json

* Update menu.json
2024-09-15 22:01:44 -04:00
sodam 6c43e97001
[Bug] fixed ME event ```trash to treasure``` wrong descriptions of the choices (#4273)
* modified script  (by ImperialSympathizer)

* removed wrong word(healing)

* removed wrong word
2024-09-15 22:01:07 -04:00
chaosgrimmon 880a46b659
[Sprite] Fix Lycanroc Midday (#4274)
* [Sprite] Midday Lycanroc back

* [Sprite] Midday Lycanroc shiny front

* [Sprite] Midday Lycanroc shiny back
2024-09-15 22:00:47 -04:00
88 changed files with 3281 additions and 805 deletions

View File

@ -55,7 +55,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to
- Pokémon Sword/Shield
- Pokémon Legends: Arceus
- Pokémon Scarlet/Violet
- Firel (Custom Laboratory, Metropolis, Seabed, and Space biome music)
- Firel (Custom Ice Cave, Laboratory, Metropolis, Plains, Power Plant, Seabed, Space, and Volcano biome music)
- Lmz (Custom Jungle biome music)
- Andr06 (Custom Slum and Sea biome music)

View File

@ -26,10 +26,36 @@ body {
#app {
display: flex;
justify-content: center;
align-items: center;
}
#app > div:first-child {
transform-origin: center !important;
}
/*
Supports automatic vertical centering as suggested in PR#1114, but only via CSS
Condition factorized to deduce CSS rules:
true if (isLandscape && !isMobile() && !hasTouchscreen() || (hasTouchscreen() && !isTouchControlsEnabled))
*/
/* isLandscape && !isMobile() && !hasTouchscreen() */
@media (orientation: landscape) and (pointer: fine) {
#app {
align-items: center;
}
}
@media (pointer: coarse) {
/* hasTouchscreen() && !isTouchControlsEnabled */
body:has(> #touchControls[class=visible]) #app {
align-items: start;
}
body:has(> #touchControls[class=visible]) #app > div:first-child {
transform-origin: top !important;
}
}
#layout:fullscreen #dpad, #layout:fullscreen {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -27,7 +27,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -115,7 +115,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -215,7 +215,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -315,7 +315,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -414,7 +414,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -538,7 +538,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 23,
@ -685,7 +685,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -19,
@ -784,7 +784,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 26,
@ -883,7 +883,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 23.5,
@ -994,7 +994,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 9,
@ -1069,7 +1069,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -18.5,
@ -1157,7 +1157,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 37.5,
@ -1221,7 +1221,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1284,7 +1284,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1348,7 +1348,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1448,7 +1448,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1548,7 +1548,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1647,7 +1647,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 0,
@ -1759,7 +1759,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -25.5,
@ -1870,7 +1870,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 12,
@ -1957,7 +1957,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -27,
@ -2044,7 +2044,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -16,
@ -2143,7 +2143,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -26.5,
@ -2230,7 +2230,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 23,
@ -2306,7 +2306,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": 24,
@ -2346,7 +2346,7 @@
"opacity": 255,
"locked": true,
"priority": 1,
"focus": 2
"focus": 1
},
{
"x": -27,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -4,114 +4,30 @@
"image": "745.png",
"format": "RGBA8888",
"size": {
"w": 300,
"h": 300
"w": 181,
"h": 181
},
"scale": 1,
"frames": [
{
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 1,
"y": 4,
"w": 60,
"h": 67
},
"frame": {
"x": 0,
"y": 0,
"w": 60,
"h": 67
}
},
{
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 1,
"y": 4,
"w": 60,
"h": 67
},
"frame": {
"x": 60,
"y": 0,
"w": 60,
"h": 67
}
},
{
"filename": "0015.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 1,
"y": 4,
"w": 60,
"h": 67
},
"frame": {
"x": 120,
"y": 0,
"w": 60,
"h": 67
}
},
{
"filename": "0016.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 1,
"y": 4,
"w": 60,
"h": 67
},
"frame": {
"x": 180,
"y": 0,
"w": 60,
"h": 67
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 1,
"y": 3,
"w": 60,
"h": 68
"y": 0,
"w": 71,
"h": 61
},
"frame": {
"x": 240,
"x": 0,
"y": 0,
"w": 60,
"h": 68
"w": 71,
"h": 61
}
},
{
@ -119,62 +35,41 @@
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 61,
"h": 68
},
"frame": {
"x": 0,
"y": 67,
"w": 61,
"h": 68
}
},
{
"filename": "0014.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 1,
"y": 3,
"w": 60,
"h": 68
"y": 0,
"w": 71,
"h": 61
},
"frame": {
"x": 61,
"y": 67,
"w": 60,
"h": 68
"x": 0,
"y": 0,
"w": 71,
"h": 61
}
},
{
"filename": "0018.png",
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 61,
"h": 68
"x": 1,
"y": 1,
"w": 71,
"h": 60
},
"frame": {
"x": 121,
"y": 67,
"w": 61,
"h": 68
"x": 71,
"y": 0,
"w": 71,
"h": 60
}
},
{
@ -182,41 +77,41 @@
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 1,
"y": 2,
"w": 60,
"h": 69
"y": 1,
"w": 71,
"h": 60
},
"frame": {
"x": 182,
"y": 68,
"w": 60,
"h": 69
"x": 71,
"y": 0,
"w": 71,
"h": 60
}
},
{
"filename": "0017.png",
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 1,
"y": 2,
"w": 60,
"h": 69
"w": 71,
"h": 59
},
"frame": {
"x": 0,
"y": 135,
"w": 60,
"h": 69
"x": 71,
"y": 60,
"w": 71,
"h": 59
}
},
{
@ -224,209 +119,104 @@
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 61,
"h": 70
},
"frame": {
"x": 60,
"y": 135,
"w": 61,
"h": 70
}
},
{
"filename": "0013.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 61,
"h": 70
},
"frame": {
"x": 121,
"y": 135,
"w": 61,
"h": 70
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 182,
"y": 137,
"w": 61,
"h": 71
}
},
{
"filename": "0011.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 182,
"y": 137,
"w": 61,
"h": 71
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
"w": 70,
"h": 61
},
"frame": {
"x": 0,
"y": 205,
"w": 61,
"h": 71
"y": 61,
"w": 70,
"h": 61
}
},
{
"filename": "0009.png",
"rotated": false,
"trimmed": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
"w": 70,
"h": 61
},
"frame": {
"x": 61,
"y": 205,
"w": 61,
"h": 71
"x": 0,
"y": 61,
"w": 70,
"h": 61
}
},
{
"filename": "0019.png",
"filename": "0001.png",
"rotated": false,
"trimmed": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 1,
"y": 2,
"w": 68,
"h": 59
},
"frame": {
"x": 0,
"y": 122,
"w": 68,
"h": 59
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
"w": 69,
"h": 61
},
"frame": {
"x": 61,
"y": 205,
"w": 61,
"h": 71
"x": 70,
"y": 119,
"w": 69,
"h": 61
}
},
{
"filename": "0010.png",
"rotated": false,
"trimmed": false,
"trimmed": true,
"sourceSize": {
"w": 61,
"h": 71
"w": 72,
"h": 61
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
"w": 69,
"h": 61
},
"frame": {
"x": 122,
"y": 208,
"w": 61,
"h": 71
}
},
{
"filename": "0020.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 122,
"y": 208,
"w": 61,
"h": 71
}
},
{
"filename": "0012.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 183,
"y": 208,
"w": 61,
"h": 71
"x": 70,
"y": 119,
"w": 69,
"h": 61
}
}
]
@ -435,6 +225,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:8d47c2cedd75d15c81c3aa0a0b14133c:28c19026319cfbbb59916e3d1b92f732:f9304907e03a5223c5bc78c934419106$"
"smartupdate": "$TexturePacker:SmartUpdate:9bdd7250af45db121574c90e718874a8:ca85d052f16849220d83acd876b20b8b:f9304907e03a5223c5bc78c934419106$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -4,30 +4,93 @@
"image": "745.png",
"format": "RGBA8888",
"size": {
"w": 189,
"h": 189
"w": 286,
"h": 286
},
"scale": 1,
"frames": [
{
"filename": "0006.png",
"filename": "0007.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 1,
"y": 0,
"w": 65,
"h": 58
"x": 0,
"y": 3,
"w": 60,
"h": 55
},
"frame": {
"x": 0,
"y": 0,
"w": 65,
"w": 60,
"h": 55
}
},
{
"filename": "0008.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 60,
"h": 55
},
"frame": {
"x": 60,
"y": 0,
"w": 60,
"h": 55
}
},
{
"filename": "0019.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 60,
"h": 55
},
"frame": {
"x": 120,
"y": 0,
"w": 60,
"h": 55
}
},
{
"filename": "0020.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 3,
"w": 60,
"h": 55
},
"frame": {
"x": 180,
"y": 0,
"w": 60,
"h": 55
}
},
{
@ -35,124 +98,418 @@
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 66,
"w": 60,
"h": 57
},
"frame": {
"x": 65,
"y": 0,
"w": 66,
"x": 0,
"y": 55,
"w": 60,
"h": 57
}
},
{
"filename": "0007.png",
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 2,
"y": 0,
"w": 64,
"h": 58
},
"frame": {
"x": 65,
"y": 57,
"w": 64,
"h": 58
}
},
{
"filename": "0003.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 66,
"h": 58
},
"spriteSourceSize": {
"x": 2,
"x": 0,
"y": 1,
"w": 64,
"w": 60,
"h": 57
},
"frame": {
"x": 0,
"y": 58,
"w": 64,
"x": 60,
"y": 55,
"w": 60,
"h": 57
}
},
{
"filename": "0004.png",
"filename": "0009.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 1,
"y": 2,
"w": 65,
"h": 56
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 120,
"y": 55,
"w": 60,
"h": 57
}
},
{
"filename": "0010.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 180,
"y": 55,
"w": 60,
"h": 57
}
},
{
"filename": "0022.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 180,
"y": 55,
"w": 60,
"h": 57
}
},
{
"filename": "0017.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 0,
"y": 115,
"w": 65,
"h": 56
"y": 112,
"w": 60,
"h": 57
}
},
{
"filename": "0018.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 60,
"y": 112,
"w": 60,
"h": 57
}
},
{
"filename": "0021.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 60,
"h": 57
},
"frame": {
"x": 120,
"y": 112,
"w": 60,
"h": 57
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"trimmed": false,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 3,
"x": 0,
"y": 0,
"w": 62,
"w": 60,
"h": 58
},
"frame": {
"x": 65,
"y": 115,
"w": 62,
"x": 180,
"y": 112,
"w": 60,
"h": 58
}
},
{
"filename": "0013.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 180,
"y": 112,
"w": 60,
"h": 58
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"trimmed": false,
"sourceSize": {
"w": 66,
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 3,
"x": 0,
"y": 0,
"w": 62,
"w": 60,
"h": 58
},
"frame": {
"x": 127,
"y": 115,
"w": 62,
"x": 0,
"y": 169,
"w": 60,
"h": 58
}
},
{
"filename": "0014.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 0,
"y": 169,
"w": 60,
"h": 58
}
},
{
"filename": "0003.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 60,
"y": 169,
"w": 60,
"h": 58
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 120,
"y": 169,
"w": 60,
"h": 58
}
},
{
"filename": "0011.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 180,
"y": 170,
"w": 60,
"h": 58
}
},
{
"filename": "0012.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 0,
"y": 227,
"w": 60,
"h": 58
}
},
{
"filename": "0024.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 0,
"y": 227,
"w": 60,
"h": 58
}
},
{
"filename": "0015.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 60,
"y": 227,
"w": 60,
"h": 58
}
},
{
"filename": "0016.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 120,
"y": 227,
"w": 60,
"h": 58
}
},
{
"filename": "0023.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 60,
"h": 58
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 60,
"h": 58
},
"frame": {
"x": 180,
"y": 228,
"w": 60,
"h": 58
}
}
@ -162,6 +519,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:1b95a218abc87c12576165b943d3cb77:4d796dc75302ca2e18ce15e67dcf3f0f:f9304907e03a5223c5bc78c934419106$"
"smartupdate": "$TexturePacker:SmartUpdate:d67741bfb78b7ff0c920c5395dd91fc2:e78172ef76e3b6327173461a595a8a6b:f9304907e03a5223c5bc78c934419106$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_ca_ES.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_de.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_es.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_fr.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_it.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_ja.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_ko.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_pt_BR.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses_zh_CN.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "statuses.png",
"format": "RGBA8888",
"size": {
"w": 22,
"h": 64
},
"scale": 1,
"frames": [
{
"filename": "pokerus",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 22,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
},
"frame": {
"x": 0,
"y": 0,
"w": 22,
"h": 8
}
},
{
"filename": "burn",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 8,
"w": 20,
"h": 8
}
},
{
"filename": "faint",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 16,
"w": 20,
"h": 8
}
},
{
"filename": "freeze",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 24,
"w": 20,
"h": 8
}
},
{
"filename": "paralysis",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 32,
"w": 20,
"h": 8
}
},
{
"filename": "poison",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 40,
"w": 20,
"h": 8
}
},
{
"filename": "sleep",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 48,
"w": 20,
"h": 8
}
},
{
"filename": "toxic",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 20,
"h": 8
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 20,
"h": 8
},
"frame": {
"x": 0,
"y": 56,
"w": 20,
"h": 8
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:37686e85605d17b806f22d43081c1139:70535ffee63ba61b3397d8470c2c8982:e6649238c018d3630e55681417c698ca$"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

View File

@ -2625,7 +2625,11 @@ export class PreStatStageChangeAbAttr extends AbAttr {
}
}
/**
* Protect one or all {@linkcode BattleStat} from reductions caused by other Pokémon's moves and Abilities
*/
export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
/** {@linkcode BattleStat} to protect or `undefined` if **all** {@linkcode BattleStat} are protected */
private protectedStat?: BattleStat;
constructor(protectedStat?: BattleStat) {
@ -2634,7 +2638,17 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
this.protectedStat = protectedStat;
}
applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): boolean {
/**
* Apply the {@linkcode ProtectedStatAbAttr} to an interaction
* @param _pokemon
* @param _passive
* @param simulated
* @param stat the {@linkcode BattleStat} being affected
* @param cancelled The {@linkcode Utils.BooleanHolder} that will be set to true if the stat is protected
* @param _args
* @returns true if the stat is protected, false otherwise
*/
applyPreStatStageChange(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, _args: any[]): boolean {
if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) {
cancelled.value = true;
return true;
@ -3757,7 +3771,7 @@ export class StatStageChangeMultiplierAbAttr extends AbAttr {
this.multiplier = multiplier;
}
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value *= this.multiplier;
return true;

View File

@ -488,14 +488,14 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
moveAnims.set(move, null);
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP;
const moveName = Moves[move].toLowerCase().replace(/\_/g, "-");
const fetchAnimAndResolve = (move: Moves) => {
scene.cachedFetch(`./battle-anims/${moveName}.json`)
scene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
.then(response => {
const contentType = response.headers.get("content-type");
if (!response.ok || contentType?.indexOf("application/json") === -1) {
console.error(`Could not load animation file for move '${moveName}'`, response.status, response.statusText);
populateMoveAnim(move, moveAnims.get(defaultMoveAnim));
useDefaultAnim(move, defaultMoveAnim);
logMissingMoveAnim(move, response.status, response.statusText);
return resolve();
}
return response.json();
@ -515,6 +515,11 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
resolve();
}
})
.catch(error => {
useDefaultAnim(move, defaultMoveAnim);
logMissingMoveAnim(move, error);
return resolve();
});
};
fetchAnimAndResolve(move);
@ -522,6 +527,29 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
});
}
/**
* Populates the default animation for the given move.
*
* @param move the move to populate an animation for
* @param defaultMoveAnim the move to use as the default animation
*/
function useDefaultAnim(move: Moves, defaultMoveAnim: Moves) {
populateMoveAnim(move, moveAnims.get(defaultMoveAnim));
}
/**
* Helper method for printing a warning to the console when a move animation is missing.
*
* @param move the move to populate an animation for
* @param optionalParams parameters to add to the error logging
*
* @remarks use {@linkcode useDefaultAnim} to use a default animation
*/
function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) {
const moveName = Utils.animationFileName(move);
console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams);
}
/**
* Fetches animation configs to be used in a Mystery Encounter
* @param scene

View File

@ -3839,7 +3839,7 @@ export class StormAccuracyAttr extends VariableAccuracyAttr {
* @extends VariableAccuracyAttr
* @see {@linkcode apply}
*/
export class MinimizeAccuracyAttr extends VariableAccuracyAttr {
export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr {
/**
* @see {@linkcode apply}
* @param user N/A
@ -4855,10 +4855,10 @@ export class RemoveAllSubstitutesAttr extends MoveEffectAttr {
* Attribute used when a move hits a {@linkcode BattlerTagType} for double damage
* @extends MoveAttr
*/
export class HitsTagAttr extends MoveAttr {
export class DealsDoubleDamageToTagAttr extends MoveAttr {
/** The {@linkcode BattlerTagType} this move hits */
public tagType: BattlerTagType;
/** Should this move deal double damage against {@linkcode HitsTagAttr.tagType}? */
/** Should this move deal double damage against {@linkcode DealsDoubleDamageToTagAttr.tagType}? */
public doubleDamage: boolean;
constructor(tagType: BattlerTagType, doubleDamage?: boolean) {
@ -6752,12 +6752,11 @@ export function initMoves() {
new AttackMove(Moves.CUT, Type.NORMAL, MoveCategory.PHYSICAL, 50, 95, 30, -1, 0, 1)
.slicingMove(),
new AttackMove(Moves.GUST, Type.FLYING, MoveCategory.SPECIAL, 40, 100, 35, -1, 0, 1)
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, true)
.windMove(),
new AttackMove(Moves.WING_ATTACK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, 0, 1),
new StatusMove(Moves.WHIRLWIND, Type.NORMAL, -1, 20, -1, -6, 1)
.attr(ForceSwitchOutAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.ignoresSubstitute()
.hidesTarget()
.windMove(),
@ -6770,8 +6769,8 @@ export function initMoves() {
new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1),
new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1),
new AttackMove(Moves.STOMP, Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 1)
.attr(MinimizeAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr),
new AttackMove(Moves.DOUBLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, 0, 1)
.attr(MultiHitAttr, MultiHitType._2),
@ -6795,8 +6794,8 @@ export function initMoves() {
.attr(OneHitKOAccuracyAttr),
new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1),
new AttackMove(Moves.BODY_SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 30, 0, 1)
.attr(MinimizeAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.WRAP),
@ -6864,7 +6863,7 @@ export function initMoves() {
new AttackMove(Moves.HYDRO_PUMP, Type.WATER, MoveCategory.SPECIAL, 110, 80, 5, -1, 0, 1),
new AttackMove(Moves.SURF, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 1)
.target(MoveTarget.ALL_NEAR_OTHERS)
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERWATER, true)
.attr(GulpMissileTagAttr),
new AttackMove(Moves.ICE_BEAM, Type.ICE, MoveCategory.SPECIAL, 90, 100, 10, 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.FREEZE),
@ -6947,18 +6946,18 @@ export function initMoves() {
new AttackMove(Moves.THUNDER, Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 1)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.attr(ThunderAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false),
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false),
new AttackMove(Moves.ROCK_THROW, Type.ROCK, MoveCategory.PHYSICAL, 50, 90, 15, -1, 0, 1)
.makesContact(false),
new AttackMove(Moves.EARTHQUAKE, Type.GROUND, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 1)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY ? 0.5 : 1)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1)
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
.attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, false)
.makesContact(false),
new AttackMove(Moves.DIG, Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 1)
.attr(ChargeAttr, ChargeAnim.DIG_CHARGING, i18next.t("moveTriggers:dugAHole", {pokemonName: "{USER}"}), BattlerTagType.UNDERGROUND)
@ -7346,8 +7345,8 @@ export function initMoves() {
new AttackMove(Moves.MAGNITUDE, Type.GROUND, MoveCategory.PHYSICAL, -1, 100, 30, -1, 0, 2)
.attr(PreMoveMessageAttr, magnitudeMessageFunc)
.attr(MagnitudePowerAttr)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY ? 0.5 : 1)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.DYNAMIC_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 50, 5, 100, 0, 2)
@ -7403,7 +7402,7 @@ export function initMoves() {
new AttackMove(Moves.CROSS_CHOP, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, -1, 0, 2)
.attr(HighCritAttr),
new AttackMove(Moves.TWISTER, Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, 20, 0, 2)
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, true)
.attr(FlinchAttr)
.windMove()
.target(MoveTarget.ALL_NEAR_ENEMIES),
@ -7435,7 +7434,7 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.DEF ], -1),
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2)
.attr(TrapAttr, BattlerTagType.WHIRLPOOL)
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERWATER, true),
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
.attr(MultiHitAttr, MultiHitType.BEAT_UP)
.attr(BeatUpAttr)
@ -7658,7 +7657,7 @@ export function initMoves() {
new AttackMove(Moves.EXTRASENSORY, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, 10, 0, 3)
.attr(FlinchAttr),
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
.attr(HitsTagAttr, BattlerTagType.FLYING)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING)
.punchingMove(),
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3)
.attr(TrapAttr, BattlerTagType.SAND_TOMB)
@ -7889,8 +7888,8 @@ export function initMoves() {
new AttackMove(Moves.DRAGON_PULSE, Type.DRAGON, MoveCategory.SPECIAL, 85, 100, 10, -1, 0, 4)
.pulseMove(),
new AttackMove(Moves.DRAGON_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, 20, 0, 4)
.attr(MinimizeAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr),
new AttackMove(Moves.POWER_GEM, Type.ROCK, MoveCategory.SPECIAL, 80, 100, 20, -1, 0, 4),
new AttackMove(Moves.DRAIN_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 4)
@ -8087,7 +8086,7 @@ export function initMoves() {
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.makesContact(false),
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
.attr(CritOnlyAttr),
@ -8100,9 +8099,9 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true)
.danceMove(),
new AttackMove(Moves.HEAVY_SLAM, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
.attr(MinimizeAccuracyAttr)
.attr(AlwaysHitMinimizeAttr)
.attr(CompareWeightPowerAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true),
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true),
new AttackMove(Moves.SYNCHRONOISE, Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 5)
.target(MoveTarget.ALL_NEAR_OTHERS)
.condition(unknownTypeCondition)
@ -8221,7 +8220,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BULLDOZE, Type.GROUND, MoveCategory.PHYSICAL, 60, 100, 20, 100, 0, 5)
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY ? 0.5 : 1)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1)
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FROST_BREATH, Type.ICE, MoveCategory.SPECIAL, 60, 90, 10, 100, 0, 5)
@ -8253,12 +8252,14 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.DEF ], -1)
.slicingMove(),
new AttackMove(Moves.HEAT_CRASH, Type.FIRE, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
.attr(MinimizeAccuracyAttr)
.attr(AlwaysHitMinimizeAttr)
.attr(CompareWeightPowerAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true),
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true),
new AttackMove(Moves.LEAF_TORNADO, Type.GRASS, MoveCategory.SPECIAL, 65, 90, 10, 50, 0, 5)
.attr(StatStageChangeAttr, [ Stat.ACC ], -1),
new AttackMove(Moves.STEAMROLLER, Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 5)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr),
new SelfStatusMove(Moves.COTTON_GUARD, Type.GRASS, -1, 10, -1, 0, 5)
.attr(StatStageChangeAttr, [ Stat.DEF ], 3, true),
@ -8271,7 +8272,7 @@ export function initMoves() {
new AttackMove(Moves.HURRICANE, Type.FLYING, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 5)
.attr(ThunderAccuracyAttr)
.attr(ConfuseAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.windMove(),
new AttackMove(Moves.HEAD_CHARGE, Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 5)
.attr(RecoilAttr)
@ -8325,9 +8326,9 @@ export function initMoves() {
.attr(LastMoveDoublePowerAttr, Moves.FUSION_FLARE)
.makesContact(false),
new AttackMove(Moves.FLYING_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, 0, 6)
.attr(MinimizeAccuracyAttr)
.attr(AlwaysHitMinimizeAttr)
.attr(FlyingTypeMultiplierAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.condition(failOnGravityCondition),
new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6)
.target(MoveTarget.USER_SIDE)
@ -8498,8 +8499,8 @@ export function initMoves() {
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.attr(HitsTagAttr, BattlerTagType.MAGNET_RISEN, false)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MAGNET_RISEN, false)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.makesContact(false)
@ -8756,6 +8757,8 @@ export function initMoves() {
.partial()
.ignoresVirtual(),
new AttackMove(Moves.MALICIOUS_MOONSAULT, Type.DARK, MoveCategory.PHYSICAL, 180, -1, 1, -1, 0, 7)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.partial()
.ignoresVirtual(),
new AttackMove(Moves.OCEANIC_OPERETTA, Type.WATER, MoveCategory.SPECIAL, 195, -1, 1, -1, 0, 7)

View File

@ -684,7 +684,7 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.GROUDON, "", SpeciesFormKey.PRIMAL, new SpeciesFormChangeItemTrigger(FormChangeItem.RED_ORB))
],
[Species.RAYQUAZA]: [
new SpeciesFormChange(Species.RAYQUAZA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeCompoundTrigger(new SpeciesFormChangeItemTrigger(FormChangeItem.RAYQUAZITE), new SpeciesFormChangeMoveLearnedTrigger(Moves.DRAGON_ASCENT)))
new SpeciesFormChange(Species.RAYQUAZA, "", SpeciesFormKey.MEGA, new SpeciesFormChangeItemTrigger(FormChangeItem.RAYQUAZITE))
],
[Species.DEOXYS]: [
new SpeciesFormChange(Species.DEOXYS, "normal", "attack", new SpeciesFormChangeItemTrigger(FormChangeItem.SHARP_METEORITE)),

View File

@ -746,7 +746,7 @@ export class Arena {
case Biome.TOWN:
return 7.288;
case Biome.PLAINS:
return 7.693;
return 17.485;
case Biome.GRASS:
return 1.995;
case Biome.TALL_GRASS:
@ -774,13 +774,13 @@ export class Arena {
case Biome.DESERT:
return 1.143;
case Biome.ICE_CAVE:
return 15.010;
return 0.000;
case Biome.MEADOW:
return 3.891;
case Biome.POWER_PLANT:
return 2.810;
return 9.447;
case Biome.VOLCANO:
return 5.116;
return 17.637;
case Biome.GRAVEYARD:
return 3.232;
case Biome.DOJO:

View File

@ -3,7 +3,7 @@ import BattleScene, { AnySound } from "../battle-scene";
import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget } from "../data/move";
import Move, { HighCritAttr, DealsDoubleDamageToTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
import * as Utils from "../utils";
@ -95,6 +95,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public metLevel: integer;
public metBiome: Biome | -1;
public metSpecies: Species;
public metWave: number;
public luck: integer;
public pauseEvolutions: boolean;
public pokerus: boolean;
@ -194,6 +195,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.luck = dataSource.luck;
this.metBiome = dataSource.metBiome;
this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true));
this.metWave = dataSource.metWave ?? (this.metBiome === -1 ? -1 : 0);
this.pauseEvolutions = dataSource.pauseEvolutions;
this.pokerus = !!dataSource.pokerus;
this.evoCounter = dataSource.evoCounter ?? 0;
@ -240,6 +242,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.metLevel = level;
this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1;
this.metSpecies = species.speciesId;
this.metWave = scene.currentBattle ? scene.currentBattle.waveIndex : -1;
this.pokerus = false;
if (level > 1) {
@ -1270,13 +1273,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @param attrType {@linkcode AbAttr} The ability attribute to check for.
* @param canApply {@linkcode Boolean} If false, it doesn't check whether the ability is currently active
* @param ignoreOverride {@linkcode Boolean} If true, it ignores ability changing effects
* @returns {AbAttr[]} A list of all the ability attributes on this ability.
* @returns A list of all the ability attributes on this ability.
*/
getAbilityAttrs(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): AbAttr[] {
const abilityAttrs: AbAttr[] = [];
getAbilityAttrs<T extends AbAttr = AbAttr>(attrType: { new(...args: any[]): T }, canApply: boolean = true, ignoreOverride?: boolean): T[] {
const abilityAttrs: T[] = [];
if (!canApply || this.canApplyAbility()) {
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs(attrType));
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs<T>(attrType));
}
if (!canApply || this.canApplyAbility(true)) {
@ -1510,7 +1513,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const immuneTags = this.findTags(tag => tag instanceof TypeImmuneTag && tag.immuneType === moveType);
for (const tag of immuneTags) {
if (move && !move.getAttrs(HitsTagAttr).some(attr => attr.tagType === tag.tagType)) {
if (move && !move.getAttrs(DealsDoubleDamageToTagAttr).some(attr => attr.tagType === tag.tagType)) {
typeMultiplier.value = 0;
break;
}
@ -2486,13 +2489,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
/**
* For each {@linkcode HitsTagAttr} the move has, doubles the damage of the move if:
* For each {@linkcode DealsDoubleDamageToTagAttr} the move has, doubles the damage of the move if:
* The target has a {@linkcode BattlerTagType} that this move interacts with
* AND
* The move doubles damage when used against that tag
*/
const hitsTagMultiplier = new Utils.NumberHolder(1);
move.getAttrs(HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
move.getAttrs(DealsDoubleDamageToTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
if (this.getTag(hta.tagType)) {
hitsTagMultiplier.value *= 2;
}
@ -4081,6 +4084,7 @@ export class PlayerPokemon extends Pokemon {
newPokemon.metLevel = this.metLevel;
newPokemon.metBiome = this.metBiome;
newPokemon.metSpecies = this.metSpecies;
newPokemon.metWave = this.metWave;
newPokemon.fusionSpecies = this.fusionSpecies;
newPokemon.fusionFormIndex = this.fusionFormIndex;
newPokemon.fusionAbilityIndex = this.fusionAbilityIndex;
@ -4088,6 +4092,7 @@ export class PlayerPokemon extends Pokemon {
newPokemon.fusionVariant = this.fusionVariant;
newPokemon.fusionGender = this.fusionGender;
newPokemon.fusionLuck = this.fusionLuck;
newPokemon.usedTMs = this.usedTMs;
this.scene.getParty().push(newPokemon);
newPokemon.evolve((!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution)), evoSpecies);
@ -4779,6 +4784,7 @@ export class EnemyPokemon extends Pokemon {
this.pokeball = pokeballType;
this.metLevel = this.level;
this.metBiome = this.scene.arena.biomeType;
this.metWave = this.scene.currentBattle.waveIndex;
this.metSpecies = this.species.speciesId;
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.variant, this.ivs, this.nature, this);

View File

@ -241,12 +241,15 @@ export class LoadingScene extends SceneBase {
const lang = i18next.resolvedLanguage;
if (lang !== "en") {
if (Utils.verifyLang(lang)) {
this.loadAtlas(`statuses_${lang}`, "");
this.loadAtlas(`types_${lang}`, "");
} else {
// Fallback to English
this.loadAtlas("statuses", "");
this.loadAtlas("types", "");
}
} else {
this.loadAtlas("statuses", "");
this.loadAtlas("types", "");
}
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"];

View File

@ -11,7 +11,7 @@
"cancel": "Abbrechen",
"memoString": "Wesen: {{natureFragment}}\n{{metFragment}}",
"metFragment": {
"normal": "Herkunft: {{biome}}\nMit Lv. {{level}} erhalten.",
"normal": "Herkunft: {{biome}} - Welle {{wave}}\nMit Lv. {{level}} erhalten.",
"apparently": "Herkunft: {{biome}}\nOffenbar mit Lv. {{level}} erhalten."
},
"natureFragment": {

View File

@ -108,7 +108,7 @@
"forest": "PMD EoS Dusk Forest",
"grass": "PMD EoS Apple Woods",
"graveyard": "PMD EoS Mystifying Forest",
"ice_cave": "PMD EoS Vast Ice Mountain",
"ice_cave": "Firel - -60F",
"island": "PMD EoS Craggy Coast",
"jungle": "Lmz - Jungle",
"laboratory": "Firel - Laboratory",
@ -116,8 +116,8 @@
"meadow": "PMD EoS Sky Peak Forest",
"metropolis": "Firel - Metropolis",
"mountain": "PMD EoS Mt. Horn",
"plains": "PMD EoS Sky Peak Prairie",
"power_plant": "PMD EoS Far Amp Plains",
"plains": "Firel - Route 888",
"power_plant": "Firel - The Klink",
"ruins": "PMD EoS Deep Sealed Ruin",
"sea": "Andr06 - Marine Mystique",
"seabed": "Firel - Seabed",
@ -128,7 +128,7 @@
"tall_grass": "PMD EoS Foggy Forest",
"temple": "PMD EoS Aegis Cave",
"town": "PMD EoS Random Dungeon Theme 3",
"volcano": "PMD EoS Steam Cave",
"volcano": "Firel - Twisturn Volcano",
"wasteland": "PMD EoS Hidden Highland",
"encounter_ace_trainer": "BW Trainers' Eyes Meet (Ace Trainer)",
"encounter_backpacker": "BW Trainers' Eyes Meet (Backpacker)",

View File

@ -6,8 +6,8 @@
"option": {
"1": {
"label": "Dig for Valuables",
"tooltip": "(-) Lose Healing Items in Shops\n(+) Gain Amazing Items",
"selected": "You wade through the garbage pile, becoming mired in filth.$There's no way any respectable shopkeepers\nwill sell you anything in your grimy state!$You'll just have to make do without shop healing items.$However, you found some incredible items in the garbage!"
"tooltip": "(-) Items in Shops Cost 3x\n(+) Gain Amazing Items",
"selected": "You wade through the garbage pile, becoming mired in filth.$There's no way any respectable shopkeeper would\nsell you items at the normal rate in your grimy state!$You'll have to pay extra for items now.$However, you found some incredible items in the garbage!"
},
"2": {
"label": "Investigate Further",

View File

@ -11,7 +11,7 @@
"cancel": "Cancel",
"memoString": "{{natureFragment}} nature,\n{{metFragment}}",
"metFragment": {
"normal": "met at Lv{{level}},\n{{biome}}.",
"normal": "met at Lv{{level}},\n{{biome}}, Wave {{wave}}.",
"apparently": "apparently met at Lv{{level}},\n{{biome}}."
},
"natureFragment": {

View File

@ -11,7 +11,7 @@
"cancel": "Salir",
"memoString": "Naturaleza {{natureFragment}},\n{{metFragment}}",
"metFragment": {
"normal": "encontrado al Nv. {{level}},\n{{biome}}.",
"normal": "encontrado al Nv. {{level}},\n{{biome}}, Oleada {{wave}}.",
"apparently": "aparentemente encontrado al Nv. {{level}},\n{{biome}}."
}
}

View File

@ -44,7 +44,10 @@
"moveNotImplemented": "{{moveName}} nest pas encore implémenté et ne peut pas être sélectionné.",
"moveNoPP": "Il ny a plus de PP pour\ncette capacité !",
"moveDisabled": "{{moveName}} est sous entrave !",
"canOnlyUseMove": "{{pokemonName}} ne peut utiliser\nque la capacité {{moveName}} !",
"moveCannotBeSelected": "La capacité {{moveName}}\nne peut pas être choisie !",
"disableInterruptedMove": "Il y a une entrave sur la capacité {{moveName}}\nde{{pokemonNameWithAffix}} !",
"throatChopInterruptedMove": "Exécu-Son empêche {{pokemonName}}\ndutiliser la capacité !",
"noPokeballForce": "Une force mystérieuse\nempêche lutilisation des Poké Balls.",
"noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, cest mal !",
"noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon !",

View File

@ -46,7 +46,7 @@
"yes": "Oui",
"no": "Non",
"disclaimer": "AVERTISSEMENT",
"disclaimerDescription": "Ce jeu nest pas un produit fini et peut contenir des problèmes de jouabilité, dont de possibles pertes de sauvegardes,\ndes modifications sans avertissement et pourrait ou non encore être mis à jour ou terminé.",
"disclaimerDescription": "Ce jeu nest pas un produit fini.\nIl peut contenir des problèmes de jouabilité, dont de possibles pertes de sauvegardes,\ndes modifications sans avertissement et pourrait à tout moment cesser dêtre mis à jour.",
"choosePokemon": "Sélectionnez un Pokémon.",
"renamePokemon": "Renommer le Pokémon",
"rename": "Renommer",

View File

@ -7,6 +7,7 @@
"switchedStat": "{{pokemonName}} et sa cible échangent leur {{stat}} !",
"sharedGuard": "{{pokemonName}} additionne sa garde à celle de sa cible et redistribue le tout équitablement !",
"sharedPower": "{{pokemonName}} additionne sa force à celle de sa cible et redistribue le tout équitablement !",
"shiftedStats": "{{pokemonName}} échange {{statToSwitch}} et {{statToSwitchWith}} !",
"goingAllOutForAttack": "{{pokemonName}} a pris\ncette capacité au sérieux !",
"regainedHealth": "{{pokemonName}}\nrécupère des PV !",
"keptGoingAndCrashed": "{{pokemonName}}\nsécrase au sol !",
@ -67,5 +68,7 @@
"swapArenaTags": "Les effets affectant chaque côté du terrain\nont été échangés par {{pokemonName}} !",
"exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !",
"safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !",
"substituteOnOverlap": "{{pokemonName}} a déjà\nun clone !",
"substituteNotEnoughHp": "Mais il est trop faible\npour créer un clone !",
"afterYou": "{{pokemonName}} accepte\navec joie !"
}

View File

@ -13,6 +13,7 @@
"ALL": "Tout",
"PASS_BATON": "Relais",
"UNPAUSE_EVOLUTION": "Réactiver Évolution",
"PAUSE_EVOLUTION": "Interrompre Évolution",
"REVIVE": "Ranimer",
"RENAME": "Renommer",
"choosePokemon": "Sélectionnez un Pokémon.",
@ -23,6 +24,7 @@
"tooManyItems": "{{pokemonName}} porte trop\ndexemplaires de cet objet !",
"anyEffect": "Cela naura aucun effet.",
"unpausedEvolutions": "{{pokemonName}} peut de nouveau évoluer.",
"pausedEvolutions": "{{pokemonName}} ne peut plus évoluer.",
"unspliceConfirmation": "Voulez-vous vraiment séparer {{fusionName}}\nde {{pokemonName}} ? {{fusionName}} sera perdu.",
"wasReverted": "{{fusionName}} est redevenu {{pokemonName}}.",
"releaseConfirmation": "Voulez-vous relâcher {{pokemonName}} ?",

View File

@ -11,7 +11,7 @@
"cancel": "Annuler",
"memoString": "{{natureFragment}} de nature,\n{{metFragment}}",
"metFragment": {
"normal": "rencontré au N.{{level}},\n{{biome}}.",
"normal": "rencontré au N.{{level}},\n{{biome}}, Vague {{wave}}.",
"apparently": "apparemment rencontré au N.{{level}},\n{{biome}}."
},
"natureFragment": {

View File

@ -94,7 +94,7 @@
"caitlin": "Percila",
"malva": "Malva",
"siebold": "Narcisse",
"wikstrom": "Tileo",
"wikstrom": "Thyméo",
"drasna": "Dracéna",
"hala": "Pectorius",
"molayne": "Molène",

View File

@ -6,5 +6,5 @@
"pokerus": "Chaque jour, 3 starters tirés aléatoirement ont un contour violet.\n$Si un starter que vous possédez la, essayez de lajouter à votre équipe. Vérifiez bien son résumé !",
"statChange": "Les changements de stats persistent à travers\nles combats tant que le Pokémon nest pas rappelé.\n$Vos Pokémon sont rappelés avant un combat de\nDresseur et avant dentrer dans un nouveau biome.\n$Vous pouvez voir en combat les changements de stats\ndun Pokémon en maintenant C ou Maj.\n$Vous pouvez également voir les capacités de ladversaire\nen maintenant V.\n$Seules les capacités que le Pokémon a utilisées dans\nce combat sont consultables.",
"selectItem": "Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre quun.\n$Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents.\n$La plupart des effets des objets non-consommables se cumuleront de diverses manières.\n$Certains objets napparaitront que sils ont une utilité immédiate, comme les objets dévolution.\n$Vous pouvez aussi transférer des objets tenus entre\nPokémon en utilisant loption de transfert.\n$Loption de transfert apparait en bas à droite dès\nquun Pokémon de léquipe porte un objet.\n$Vous pouvez acheter des consommables avec de\nlargent. Plus vous progressez, plus le choix sera large.\n$Choisir un des objets gratuits déclenchera le prochain\ncombat, donc faites bien tous vos achats avant.",
"eggGacha": "Depuis cet écran, vous pouvez utiliser vos coupons\npour recevoir Œufs de Pokémon au hasard.\n$Les Œufs éclosent après avoir remporté un certain nombre de combats. Plus ils sont rares, plus ils mettent de temps.\n$Les Pokémon éclos ne rejoindront pas votre équipe, mais seront ajoutés à vos starters.\n$Les Pokémon issus dŒufs ont généralement de meilleurs IV que les Pokémon sauvages.\n$Certains Pokémon ne peuvent être obtenus que dans des Œufs.\n$Il y a 3 différentes machines à actionner avec différents\nbonus, prenez celle qui vous convient le mieux !"
"eggGacha": "Depuis cet écran, vous pouvez utiliser vos coupons\npour recevoir Œufs de Pokémon au hasard.\n$Les Œufs éclosent après avoir remporté un certain nombre de combats.\n$Plus ils sont rares, plus ils mettent de temps.\n$Les Pokémon éclos ne rejoindront pas votre équipe, mais seront ajoutés à vos starters.\n$Les Pokémon issus dŒufs ont généralement de meilleurs IV que les Pokémon sauvages.\n$Certains Pokémon ne peuvent être obtenus que dans des Œufs.\n$Il y a 3 différentes machines à actionner avec différents\nbonus, prenez celle qui vous convient le mieux !"
}

View File

@ -11,7 +11,7 @@
"cancel": "Annulla",
"memoString": "Natura {{natureFragment}},\n{{metFragment}}",
"metFragment": {
"normal": "incontrato al Lv.{{level}},\n{{biome}}.",
"normal": "incontrato al Lv.{{level}},\n{{biome}}, Onda {{wave}}.",
"apparently": "apparentemente incontrato al Lv.{{level}},\n{{biome}}."
}
}

View File

@ -11,7 +11,7 @@
"cancel": "キャンセル",
"memoString": "{{natureFragment}}な性格。\n{{metFragment}}",
"metFragment": {
"normal": "{{biome}}で\nLv.{{level}}の時に出会った。",
"normal": "ラウンド{{wave}}に{{biome}}で\nLv.{{level}}の時に出会った。",
"apparently": "{{biome}}で\nLv.{{level}}の時に出会ったようだ。"
},
"natureFragment": {

View File

@ -13,8 +13,10 @@
"ALL": "전부",
"PASS_BATON": "배턴터치한다",
"UNPAUSE_EVOLUTION": "진화 재개",
"PAUSE_EVOLUTION": "진화 중지",
"REVIVE": "되살린다",
"RENAME": "닉네임 바꾸기",
"SELECT": "선택한다",
"choosePokemon": "포켓몬을 선택하세요.",
"doWhatWithThisPokemon": "포켓몬을 어떻게 하겠습니까?",
"noEnergy": "{{pokemonName}}[[는]] 싸울 수 있는\n기력이 남아 있지 않습니다!",
@ -23,6 +25,7 @@
"tooManyItems": "{{pokemonName}}[[는]] 지닌 도구의 수가\n너무 많습니다",
"anyEffect": "써도 효과가 없다.",
"unpausedEvolutions": "{{pokemonName}}의 진화가 재개되었다.",
"pausedEvolutions": "{{pokemonName}}[[가]] 진화하지 않도록 했다.",
"unspliceConfirmation": "{{pokemonName}}로부터 {{fusionName}}의 융합을 해제하시겠습니까?\n{{fusionName}}는 사라지게 됩니다.",
"wasReverted": "{{fusionName}}은 {{pokemonName}}의 모습으로 돌아갔습니다!",
"releaseConfirmation": "{{pokemonName}}[[를]]\n정말 놓아주겠습니까?",

View File

@ -11,7 +11,7 @@
"cancel": "그만둔다",
"memoString": "{{natureFragment}}.\n{{metFragment}}",
"metFragment": {
"normal": "{{biome}}에서\n레벨 {{level}}일 때 만났다.",
"normal": "{{biome}}에서 웨이브{{wave}},\n레벨 {{level}}일 때 만났다.",
"apparently": "{{biome}}에서\n레벨 {{level}}일 때 만난 것 같다."
},
"natureFragment": {

View File

@ -11,6 +11,10 @@
"expGainsSpeed": "경험치 획득 속도",
"expPartyDisplay": "파티 경험치 표시",
"skipSeenDialogues": "본 대화 생략",
"eggSkip": "알 스킵",
"never": "안 함",
"always": "항상",
"ask": "확인하기",
"battleStyle": "시합 룰",
"enableRetries": "재도전 허용",
"hideIvs": "개체값탐지기 효과 끄기",

View File

@ -11,7 +11,7 @@
"cancel": "Cancelar",
"memoString": "Natureza {{natureFragment}},\n{{metFragment}}",
"metFragment": {
"normal": "encontrado no Nv.{{level}},\n{{biome}}.",
"normal": "encontrado no Nv.{{level}},\n{{biome}}, Onda {{wave}}.",
"apparently": "aparentemente encontrado no Nv.{{level}},\n{{biome}}."
},
"natureFragment": {

View File

@ -12,7 +12,7 @@
"memoString": "{{natureFragment}} 性格,\n{{metFragment}}",
"metFragment": {
"normal": "met at Lv{{level}},\n{{biome}}.",
"normal": "met at Lv{{level}},\n{{biome}}, Wave {{wave}}.",
"apparently": "命中注定般地相遇于Lv.{{level}}\n{{biome}}。"
},
"natureFragment": {

View File

@ -70,6 +70,8 @@ class DefaultOverrides {
[PokeballType.MASTER_BALL]: 0,
},
};
/** Set to `true` to show all tutorials */
readonly BYPASS_TUTORIAL_SKIP: boolean = false;
// ----------------
// PLAYER OVERRIDES

View File

@ -216,8 +216,8 @@ export class EncounterPhase extends BattlePhase {
this.scene.ui.setMode(Mode.MESSAGE).then(() => {
if (!this.loaded) {
//@ts-ignore
this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore
this.trySetWeatherIfNewBiome(); // Set weather before session gets saved
this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || (this.scene.lastSavePlayTime ?? 0) >= 300).then(success => {
this.scene.disableMenu = false;
if (!success) {
return this.scene.reset(true);
@ -250,10 +250,6 @@ export class EncounterPhase extends BattlePhase {
}
}
if (!this.loaded) {
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
}
const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({
targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(),
@ -519,4 +515,18 @@ export class EncounterPhase extends BattlePhase {
}
return false;
}
/**
* Set biome weather if and only if this encounter is the start of a new biome.
*
* By using function overrides, this should happen if and only if this phase
* is exactly a NewBiomeEncounterPhase or an EncounterPhase (to account for
* Wave 1 of a Daily Run), but NOT NextEncounterPhase (which starts the next
* wave in the same biome).
*/
trySetWeatherIfNewBiome(): void {
if (!this.loaded) {
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
}
}
}

View File

@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr,
import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag";
import { MoveAnim } from "#app/data/battle-anims";
import { BattlerTagLapseType, DamageProtectedTag, ProtectedTag, SemiInvulnerableTag, SubstituteTag } from "#app/data/battler-tags";
import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move";
import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, DealsDoubleDamageToTagAttr } from "#app/data/move";
import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Moves } from "#app/enums/moves";
@ -394,7 +394,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
if (semiInvulnerableTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) {
if (semiInvulnerableTag && !this.move.getMove().getAttrs(DealsDoubleDamageToTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) {
return false;
}

View File

@ -17,8 +17,6 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
}
}
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
for (const pokemon of this.scene.getParty().filter(p => p.isOnField())) {
applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null);
}
@ -41,4 +39,11 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
}
});
}
/**
* Set biome weather.
*/
trySetWeatherIfNewBiome(): void {
this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false);
}
}

View File

@ -67,4 +67,10 @@ export class NextEncounterPhase extends EncounterPhase {
}
});
}
/**
* Do nothing (since this is simply the next wave in the same biome).
*/
trySetWeatherIfNewBiome(): void {
}
}

View File

@ -6,7 +6,7 @@ import Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import { ResetNegativeStatStageModifier } from "#app/modifier/modifier";
import { handleTutorial, Tutorial } from "#app/tutorial";
import * as Utils from "#app/utils";
import { NumberHolder, BooleanHolder } from "#app/utils";
import i18next from "i18next";
import { PokemonPhase } from "./pokemon-phase";
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
@ -42,17 +42,23 @@ export class StatStageChangePhase extends PokemonPhase {
return this.end();
}
const stages = new NumberHolder(this.stages);
if (!this.ignoreAbilities) {
applyAbAttrs(StatStageChangeMultiplierAbAttr, pokemon, null, false, stages);
}
let simulate = false;
const filteredStats = this.stats.filter(stat => {
const cancelled = new Utils.BooleanHolder(false);
const cancelled = new BooleanHolder(false);
if (!this.selfTarget && this.stages < 0) {
if (!this.selfTarget && stages.value < 0) {
// TODO: Include simulate boolean when tag applications can be simulated
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled);
}
if (!cancelled.value && !this.selfTarget && this.stages < 0) {
if (!cancelled.value && !this.selfTarget && stages.value < 0) {
applyPreStatStageChangeAbAttrs(ProtectStatAbAttr, pokemon, stat, cancelled, simulate);
}
@ -64,12 +70,6 @@ export class StatStageChangePhase extends PokemonPhase {
return !cancelled.value;
});
const stages = new Utils.IntegerHolder(this.stages);
if (!this.ignoreAbilities) {
applyAbAttrs(StatStageChangeMultiplierAbAttr, pokemon, null, false, stages);
}
const relLevels = filteredStats.map(s => (stages.value >= 1 ? Math.min(pokemon.getStatStage(s) + stages.value, 6) : Math.max(pokemon.getStatStage(s) + stages.value, -6)) - pokemon.getStatStage(s));
this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels);

View File

@ -38,8 +38,9 @@ export default class PokemonData {
public status: Status | null;
public friendship: integer;
public metLevel: integer;
public metBiome: Biome | -1;
public metBiome: Biome | -1; // -1 for starters
public metSpecies: Species;
public metWave: number; // 0 for unknown (previous saves), -1 for starters
public luck: integer;
public pauseEvolutions: boolean;
public pokerus: boolean;
@ -90,14 +91,14 @@ export default class PokemonData {
this.metLevel = source.metLevel || 5;
this.metBiome = source.metBiome !== undefined ? source.metBiome : -1;
this.metSpecies = source.metSpecies;
this.metWave = source.metWave ?? (this.metBiome === -1 ? -1 : 0);
this.luck = source.luck !== undefined ? source.luck : (source.shiny ? (source.variant + 1) : 0);
if (!forHistory) {
this.pauseEvolutions = !!source.pauseEvolutions;
this.evoCounter = source.evoCounter ?? 0;
}
this.pokerus = !!source.pokerus;
this.evoCounter = source.evoCounter ?? 0;
this.fusionSpecies = sourcePokemon ? sourcePokemon.fusionSpecies?.speciesId : source.fusionSpecies;
this.fusionFormIndex = source.fusionFormIndex;
this.fusionAbilityIndex = source.fusionAbilityIndex;

View File

@ -31,7 +31,7 @@ describe("Abilities - Contrary", () => {
});
it("should invert stat changes when applied", async() => {
await game.startBattle([
await game.classicMode.startBattle([
Species.SLOWBRO
]);
@ -39,4 +39,39 @@ describe("Abilities - Contrary", () => {
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
}, 20000);
describe("With Clear Body", () => {
it("should apply positive effects", async () => {
game.override
.enemyPassiveAbility(Abilities.CLEAR_BODY)
.moveset([Moves.TAIL_WHIP]);
await game.classicMode.startBattle([Species.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
game.move.select(Moves.TAIL_WHIP);
await game.phaseInterceptor.to("TurnEndPhase");
expect(enemyPokemon.getStatStage(Stat.DEF)).toBe(1);
});
it("should block negative effects", async () => {
game.override
.enemyPassiveAbility(Abilities.CLEAR_BODY)
.enemyMoveset([Moves.HOWL, Moves.HOWL, Moves.HOWL, Moves.HOWL])
.moveset([Moves.SPLASH]);
await game.classicMode.startBattle([Species.SLOWBRO]);
const enemyPokemon = game.scene.getEnemyPokemon()!;
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("TurnEndPhase");
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
});
});
});

View File

@ -26,16 +26,16 @@ describe("Arena - Grassy Terrain", () => {
game.override
.battleType("single")
.disableCrits()
.enemyLevel(30)
.enemySpecies(Species.SNORLAX)
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH)
.enemyLevel(1)
.enemySpecies(Species.SHUCKLE)
.enemyAbility(Abilities.STURDY)
.enemyMoveset(Moves.FLY)
.moveset([Moves.GRASSY_TERRAIN, Moves.EARTHQUAKE])
.ability(Abilities.BALL_FETCH);
.ability(Abilities.NO_GUARD);
});
it("halves the damage of Earthquake", async () => {
await game.classicMode.startBattle([Species.FEEBAS]);
await game.classicMode.startBattle([Species.TAUROS]);
const eq = allMoves[Moves.EARTHQUAKE];
vi.spyOn(eq, "calculateBattlePower");
@ -53,4 +53,19 @@ describe("Arena - Grassy Terrain", () => {
expect(eq.calculateBattlePower).toHaveReturnedWith(50);
}, TIMEOUT);
it("Does not halve the damage of Earthquake if opponent is not grounded", async () => {
await game.classicMode.startBattle([Species.NINJASK]);
const eq = allMoves[Moves.EARTHQUAKE];
vi.spyOn(eq, "calculateBattlePower");
game.move.select(Moves.GRASSY_TERRAIN);
await game.toNextTurn();
game.move.select(Moves.EARTHQUAKE);
await game.phaseInterceptor.to("BerryPhase");
expect(eq.calculateBattlePower).toHaveReturnedWith(100);
}, TIMEOUT);
});

View File

@ -24,7 +24,8 @@ import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { Biome } from "#app/enums/biome";
describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game;
@ -290,22 +291,27 @@ describe("Test Battle Phase", () => {
expect(game.scene.currentBattle.turn).toBeGreaterThan(turn);
}, 20000);
it("to next wave with pokemon killed, single", async () => {
it("does not set new weather if staying in same biome", async () => {
const moveToUse = Moves.SPLASH;
game.override.battleType("single");
game.override.starterSpecies(Species.MEWTWO);
game.override.enemySpecies(Species.RATTATA);
game.override.enemyAbility(Abilities.HYDRATION);
game.override.ability(Abilities.ZEN_MODE);
game.override.startingLevel(2000);
game.override.startingWave(3);
game.override.moveset([moveToUse]);
game.override
.battleType("single")
.starterSpecies(Species.MEWTWO)
.enemySpecies(Species.RATTATA)
.enemyAbility(Abilities.HYDRATION)
.ability(Abilities.ZEN_MODE)
.startingLevel(2000)
.startingWave(3)
.startingBiome(Biome.LAKE)
.moveset([moveToUse]);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
await game.startBattle();
await game.classicMode.startBattle();
const waveIndex = game.scene.currentBattle.waveIndex;
game.move.select(moveToUse);
vi.spyOn(game.scene.arena, "trySetWeather");
await game.doKillOpponents();
await game.toNextWave();
expect(game.scene.arena.trySetWeather).not.toHaveBeenCalled();
expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex);
}, 20000);

View File

@ -0,0 +1,58 @@
import { BattlerIndex } from "#app/battle";
import { allMoves } from "#app/data/move";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { DamageCalculationResult } from "#app/field/pokemon";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe("Moves - Steamroller", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override.moveset([Moves.STEAMROLLER]).battleType("single").enemyAbility(Abilities.BALL_FETCH);
});
it("should always hit a minimzed target with double damage", async () => {
game.override.enemySpecies(Species.DITTO).enemyMoveset(Moves.MINIMIZE);
await game.classicMode.startBattle([Species.IRON_BOULDER]);
const ditto = game.scene.getEnemyPokemon()!;
vi.spyOn(ditto, "getAttackDamage");
ditto.hp = 5000;
const steamroller = allMoves[Moves.STEAMROLLER];
vi.spyOn(steamroller, "calculateBattleAccuracy");
const ironBoulder = game.scene.getPlayerPokemon()!;
vi.spyOn(ironBoulder, "getAccuracyMultiplier");
// Turn 1
game.move.select(Moves.STEAMROLLER);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.toNextTurn();
// Turn 2
game.move.select(Moves.STEAMROLLER);
await game.toNextTurn();
const [dmgCalcTurn1, dmgCalcTurn2]: DamageCalculationResult[] = vi
.mocked(ditto.getAttackDamage)
.mock.results.map((r) => r.value);
expect(dmgCalcTurn2.damage).toBeGreaterThanOrEqual(dmgCalcTurn1.damage * 2);
expect(ditto.getTag(BattlerTagType.MINIMIZED)).toBeDefined();
expect(steamroller.calculateBattleAccuracy).toHaveReturnedWith(-1);
});
});

View File

@ -0,0 +1,53 @@
import { BattlerIndex } from "#app/battle";
import { allMoves } from "#app/data/move";
import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
describe("Moves - Whirlwind", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.WHIRLWIND)
.enemySpecies(Species.PIDGEY);
});
it.each([
{ move: Moves.FLY, name: "Fly" },
{ move: Moves.BOUNCE, name: "Bounce" },
{ move: Moves.SKY_DROP, name: "Sky Drop" },
])("should not hit a flying target: $name (=$move)", async ({ move }) => {
game.override.moveset([move]);
await game.classicMode.startBattle([Species.STARAPTOR]);
const staraptor = game.scene.getPlayerPokemon()!;
const whirlwind = allMoves[Moves.WHIRLWIND];
vi.spyOn(whirlwind, "getFailedText");
game.move.select(move);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.toNextTurn();
expect(staraptor.findTag((t) => t.tagType === BattlerTagType.FLYING)).toBeDefined();
expect(whirlwind.getFailedText).toHaveBeenCalledOnce();
});
});

View File

@ -38,16 +38,15 @@ describe("Reload", () => {
it("should not have RNG inconsistencies after a biome switch", async () => {
game.override
.startingWave(10)
.startingBiome(Biome.CAVE) // Will lead to biomes with randomly generated weather
.battleType("single")
.startingLevel(100)
.enemyLevel(1000)
.startingLevel(100) // Avoid levelling up
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
.disableTrainerWaves()
.moveset([Moves.KOWTOW_CLEAVE])
.enemyMoveset(Moves.SPLASH);
await game.dailyMode.startBattle();
// Transition from Daily Run Wave 10 to Wave 11 in order to trigger biome switch
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents();
@ -63,6 +62,34 @@ describe("Reload", () => {
expect(preReloadRngState).toBe(postReloadRngState);
}, 20000);
it("should not have weather inconsistencies after a biome switch", async () => {
game.override
.startingWave(10)
.startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather
.battleType("single")
.startingLevel(100) // Avoid levelling up
.enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
.disableTrainerWaves()
.moveset([Moves.KOWTOW_CLEAVE])
.enemyMoveset(Moves.SPLASH);
await game.classicMode.startBattle(); // Apparently daily mode would override the biome
// Transition from Wave 10 to Wave 11 in order to trigger biome switch
game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents();
await game.toNextWave();
expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase");
const preReloadWeather = game.scene.arena.weather;
await game.reload.reloadSession();
const postReloadWeather = game.scene.arena.weather;
expect(postReloadWeather).toStrictEqual(preReloadWeather);
}, 20000);
it("should not have RNG inconsistencies at a Daily run wild Pokemon fight", async () => {
await game.dailyMode.startBattle();

View File

@ -31,7 +31,6 @@ import TargetSelectUiHandler from "#app/ui/target-select-ui-handler";
import { Mode } from "#app/ui/ui";
import { Button } from "#enums/buttons";
import { ExpNotification } from "#enums/exp-notification";
import { GameDataType } from "#enums/game-data-type";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils";
@ -371,13 +370,11 @@ export default class GameManager {
* @returns A promise that resolves with the exported save data.
*/
exportSaveToTest(): Promise<string> {
const saveKey = "x0i2O7WRiANTqPmZ";
return new Promise(async (resolve) => {
await this.scene.gameData.saveAll(this.scene, true, true, true, true);
this.scene.reset(true);
await waitUntil(() => this.scene.ui?.getMode() === Mode.TITLE);
await this.scene.gameData.tryExportData(GameDataType.SESSION, 0);
await waitUntil(() => localStorage.hasOwnProperty("toExport"));
return resolve(localStorage.getItem("toExport")!); // TODO: is this bang correct?;
const sessionSaveData = this.scene.gameData.getSessionSaveData(this.scene);
const encryptedSaveData = AES.encrypt(JSON.stringify(sessionSaveData), saveKey).toString();
resolve(encryptedSaveData);
});
}

View File

@ -5,11 +5,27 @@ import { vi } from "vitest";
import { BattleStyle } from "#app/enums/battle-style";
import { CommandPhase } from "#app/phases/command-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { SessionSaveData } from "#app/system/game-data";
import GameManager from "../gameManager";
/**
* Helper to allow reloading sessions in unit tests.
*/
export class ReloadHelper extends GameManagerHelper {
sessionData: SessionSaveData;
constructor(game: GameManager) {
super(game);
// Whenever the game saves the session, save it to the reloadHelper instead
vi.spyOn(game.scene.gameData, "saveAll").mockImplementation((scene) => {
return new Promise<boolean>((resolve, reject) => {
this.sessionData = scene.gameData.getSessionSaveData(scene);
resolve(true);
});
});
}
/**
* Simulate reloading the session from the title screen, until reaching the
* beginning of the first turn (equivalent to running `startBattle()`) for
@ -17,7 +33,6 @@ export class ReloadHelper extends GameManagerHelper {
*/
async reloadSession() : Promise<void> {
const scene = this.game.scene;
const sessionData = scene.gameData.getSessionSaveData(scene);
const titlePhase = new TitlePhase(scene);
scene.clearPhaseQueue();
@ -25,7 +40,7 @@ export class ReloadHelper extends GameManagerHelper {
// Set the last saved session to the desired session data
vi.spyOn(scene.gameData, "getSession").mockReturnValue(
new Promise((resolve, reject) => {
resolve(sessionData);
resolve(this.sessionData);
})
);
scene.unshiftPhase(titlePhase);

View File

@ -1,7 +1,9 @@
import BattleScene from "./battle-scene";
import AwaitableUiHandler from "./ui/awaitable-ui-handler";
import UiHandler from "./ui/ui-handler";
import { Mode } from "./ui/ui";
import i18next from "i18next";
import Overrides from "#app/overrides";
export enum Tutorial {
Intro = "INTRO",
@ -63,26 +65,87 @@ const tutorialHandlers = {
},
};
export function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> {
return new Promise<boolean>(resolve => {
if (!scene.enableTutorials) {
return resolve(false);
/**
* Run through the specified tutorial if it hasn't been seen before and mark it as seen once done
* This will show a tutorial overlay if defined in the current {@linkcode AwaitableUiHandler}
* The main menu will also get disabled while the tutorial is running
* @param scene the current {@linkcode BattleScene}
* @param tutorial the {@linkcode Tutorial} to play
* @returns a promise with result `true` if the tutorial was run and finished, `false` otherwise
*/
export async function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> {
if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP) {
return false;
}
if (scene.gameData.getTutorialFlags()[tutorial]) {
return resolve(false);
if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP) {
return false;
}
const handler = scene.ui.getHandler();
const isMenuDisabled = scene.disableMenu;
// starting tutorial, disable menu
scene.disableMenu = true;
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = true;
}
tutorialHandlers[tutorial](scene).then(() => {
await showTutorialOverlay(scene, handler);
await tutorialHandlers[tutorial](scene);
await hideTutorialOverlay(scene, handler);
// tutorial finished and overlay gone, re-enable menu, save tutorial as seen
scene.disableMenu = isMenuDisabled;
scene.gameData.saveTutorialFlag(tutorial, true);
if (handler instanceof AwaitableUiHandler) {
handler.tutorialActive = false;
}
resolve(true);
});
});
return true;
}
/**
* Show the tutorial overlay if there is one
* @param scene the current BattleScene
* @param handler the current UiHandler
* @returns `true` once the overlay has finished appearing, or if there is no overlay
*/
async function showTutorialOverlay(scene: BattleScene, handler: UiHandler) {
if (handler instanceof AwaitableUiHandler && handler.tutorialOverlay) {
scene.tweens.add({
targets: handler.tutorialOverlay,
alpha: 0.5,
duration: 750,
ease: "Sine.easeOut",
onComplete: () => {
return true;
}
});
} else {
return true;
}
}
/**
* Hide the tutorial overlay if there is one
* @param scene the current BattleScene
* @param handler the current UiHandler
* @returns `true` once the overlay has finished disappearing, or if there is no overlay
*/
async function hideTutorialOverlay(scene: BattleScene, handler: UiHandler) {
if (handler instanceof AwaitableUiHandler && handler.tutorialOverlay) {
scene.tweens.add({
targets: handler.tutorialOverlay,
alpha: 0,
duration: 500,
ease: "Sine.easeOut",
onComplete: () => {
return true;
}
});
} else {
return true;
}
}

View File

@ -7,6 +7,7 @@ export default abstract class AwaitableUiHandler extends UiHandler {
protected awaitingActionInput: boolean;
protected onActionInput: Function | null;
public tutorialActive: boolean = false;
public tutorialOverlay: Phaser.GameObjects.Rectangle;
constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode);
@ -24,4 +25,21 @@ export default abstract class AwaitableUiHandler extends UiHandler {
return false;
}
/**
* Create a semi transparent overlay that will get shown during tutorials
* @param container the container to add the overlay to
*/
initTutorialOverlay(container: Phaser.GameObjects.Container) {
if (!this.tutorialOverlay) {
this.tutorialOverlay = new Phaser.GameObjects.Rectangle(this.scene, -1, -1, this.scene.scaledCanvas.width, this.scene.scaledCanvas.height, 0x070707);
this.tutorialOverlay.setName("tutorial-overlay");
this.tutorialOverlay.setOrigin(0, 0);
this.tutorialOverlay.setAlpha(0);
}
if (container) {
container.add(this.tutorialOverlay);
}
}
}

View File

@ -162,7 +162,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains);
this.add(this.splicedIcon);
this.statusIndicator = this.scene.add.sprite(0, 0, "statuses");
this.statusIndicator = this.scene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses"));
this.statusIndicator.setName("icon_status");
this.statusIndicator.setVisible(false);
this.statusIndicator.setOrigin(0, 0);

View File

@ -83,12 +83,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
this.nameBoxContainer.add(this.nameText);
messageContainer.add(this.nameBoxContainer);
const prompt = this.scene.add.sprite(0, 0, "prompt");
prompt.setVisible(false);
prompt.setOrigin(0, 0);
messageContainer.add(prompt);
this.prompt = prompt;
this.initPromptSprite(messageContainer);
const levelUpStatsContainer = this.scene.add.container(0, 0);
levelUpStatsContainer.setVisible(false);

View File

@ -287,7 +287,6 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.eggGachaContainer.add(this.eggGachaSummaryContainer);
const gachaMessageBoxContainer = this.scene.add.container(0, 148);
this.eggGachaContainer.add(gachaMessageBoxContainer);
const gachaMessageBox = addWindow(this.scene, 0, 0, 320, 32);
gachaMessageBox.setOrigin(0, 0);
@ -301,8 +300,11 @@ export default class EggGachaUiHandler extends MessageUiHandler {
this.message = gachaMessageText;
this.initTutorialOverlay(this.eggGachaContainer);
this.eggGachaContainer.add(gachaMessageBoxContainer);
this.initPromptSprite(gachaMessageBoxContainer);
this.setCursor(0);
}

View File

@ -45,12 +45,7 @@ export default class EvolutionSceneHandler extends MessageUiHandler {
this.message = message;
const prompt = this.scene.add.sprite(0, 0, "prompt");
prompt.setVisible(false);
prompt.setOrigin(0, 0);
this.messageContainer.add(prompt);
this.prompt = prompt;
this.initPromptSprite(this.messageContainer);
}
show(_args: any[]): boolean {

View File

@ -157,6 +157,9 @@ export default class MenuUiHandler extends MessageUiHandler {
menuMessageText.setOrigin(0, 0);
this.menuMessageBoxContainer.add(menuMessageText);
this.initTutorialOverlay(this.menuContainer);
this.initPromptSprite(this.menuMessageBoxContainer);
this.message = menuMessageText;
// By default we use the general purpose message window
@ -433,6 +436,9 @@ export default class MenuUiHandler extends MessageUiHandler {
this.scene.playSound("ui/menu_open");
// Make sure the tutorial overlay sits above everything, but below the message box
this.menuContainer.bringToTop(this.tutorialOverlay);
this.menuContainer.bringToTop(this.menuMessageBoxContainer);
handleTutorial(this.scene, Tutorial.Menu);
this.bgmBar.toggleBgmBar(true);

View File

@ -17,6 +17,23 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
this.pendingPrompt = false;
}
/**
* Add the sprite to be displayed at the end of messages with prompts
* @param container the container to add the sprite to
*/
initPromptSprite(container: Phaser.GameObjects.Container) {
if (!this.prompt) {
const promptSprite = this.scene.add.sprite(0, 0, "prompt");
promptSprite.setVisible(false);
promptSprite.setOrigin(0, 0);
this.prompt = promptSprite;
}
if (container) {
container.add(this.prompt);
}
}
showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) {
this.showTextInternal(text, delay, callback, callbackDelay, prompt, promptDelay);
}
@ -180,7 +197,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const lastLineWidth = lastLineTest.displayWidth;
lastLineTest.destroy();
if (this.prompt) {
this.prompt.setPosition(lastLineWidth + 2, (textLinesCount - 1) * 18 + 2);
this.prompt.setPosition(this.message.x + lastLineWidth + 2, this.message.y + (textLinesCount - 1) * 18 + 2);
this.prompt.play("prompt");
}
this.pendingPrompt = false;

View File

@ -91,7 +91,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
valuesBg.setOrigin(0, 0);
this.val.add(valuesBg);
this.typ = this.scene.add.sprite(25, EFF_HEIGHT - 35, `types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}`, "unknown");
this.typ = this.scene.add.sprite(25, EFF_HEIGHT - 35, Utils.getLocalizedSpriteKey("types"), "unknown");
this.typ.setScale(0.8);
this.val.add(this.typ);
@ -138,7 +138,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
this.typ.setTexture(`types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}`, Type[move.type].toLowerCase());
this.typ.setTexture(Utils.getLocalizedSpriteKey("types"), Type[move.type].toLowerCase());
this.cat.setFrame(MoveCategory[move.category].toLowerCase());
this.desc.setText(move?.effect || "");

View File

@ -1272,7 +1272,7 @@ class PartySlot extends Phaser.GameObjects.Container {
}
if (this.pokemon.status) {
const statusIndicator = this.scene.add.sprite(0, 0, "statuses");
const statusIndicator = this.scene.add.sprite(0, 0, Utils.getLocalizedSpriteKey("statuses"));
statusIndicator.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase());
statusIndicator.setOrigin(0, 0);
statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 0);

View File

@ -760,7 +760,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonCaughtHatchedContainer.add(this.pokemonHatchedCountText);
this.pokemonMovesContainer = this.scene.add.container(102, 16);
this.pokemonMovesContainer.setScale(0.5);
this.pokemonMovesContainer.setScale(0.375);
for (let m = 0; m < 4; m++) {
const moveContainer = this.scene.add.container(0, 14 * m);
@ -894,6 +894,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.message.setOrigin(0, 0);
this.starterSelectMessageBoxContainer.add(this.message);
// arrow icon for the message box
this.initPromptSprite(this.starterSelectMessageBoxContainer);
this.statsContainer = new StatsContainer(this.scene, 6, 16);
this.scene.add.existing(this.statsContainer);
@ -911,7 +914,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
y: this.scene.game.canvas.height / 6 - MoveInfoOverlay.getHeight(overlayScale) - 29,
});
this.starterSelectContainer.add(this.moveInfoOverlay);
// Filter bar sits above everything, except the tutorial overlay and message box
this.starterSelectContainer.bringToTop(this.filterBarContainer);
this.initTutorialOverlay(this.starterSelectContainer);
this.starterSelectContainer.bringToTop(this.starterSelectMessageBoxContainer);
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));

View File

@ -4,12 +4,15 @@ import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./t
import { PERMANENT_STATS, getStatKey } from "#app/enums/stat";
import i18next from "i18next";
const ivChartSize = 24;
const ivChartStatCoordMultipliers = [[0, -1], [0.825, -0.5], [0.825, 0.5], [-0.825, -0.5], [-0.825, 0.5], [0, 1]];
const speedLabelOffset = -3;
const sideLabelOffset = 1;
const ivLabelOffset = [0, sideLabelOffset, -sideLabelOffset, sideLabelOffset, -sideLabelOffset, speedLabelOffset];
const ivChartLabelyOffset= [0, 5, 0, 5, 0, 0]; // doing this so attack does not overlap with (+N)
const ivChartStatIndexes = [0, 1, 2, 5, 4, 3]; // swap special attack and speed
const defaultIvChartData = new Array(12).fill(null).map(() => 0);
export class StatsContainer extends Phaser.GameObjects.Container {
@ -29,7 +32,6 @@ export class StatsContainer extends Phaser.GameObjects.Container {
setup() {
this.setName("stats");
const ivChartBgData = new Array(6).fill(null).map((_, i: integer) => [ ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][0], ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][1] ] ).flat();
const ivChartBg = this.scene.add.polygon(48, 44, ivChartBgData, 0xd8e0f0, 0.625);
ivChartBg.setOrigin(0, 0);
@ -55,12 +57,19 @@ export class StatsContainer extends Phaser.GameObjects.Container {
this.ivStatValueTexts = [];
for (const s of PERMANENT_STATS) {
const statLabel = addTextObject(this.scene, ivChartBg.x + (ivChartSize) * ivChartStatCoordMultipliers[s][0] * 1.325, ivChartBg.y + (ivChartSize) * ivChartStatCoordMultipliers[s][1] * 1.325 - 4 + ivLabelOffset[s], i18next.t(getStatKey(s)), TextStyle.TOOLTIP_CONTENT);
const statLabel = addTextObject(
this.scene,
ivChartBg.x + (ivChartSize) * ivChartStatCoordMultipliers[s][0] * 1.325 + (this.showDiff ? 0 : ivLabelOffset[s]),
ivChartBg.y + (ivChartSize) * ivChartStatCoordMultipliers[s][1] * 1.325 - 4 + (this.showDiff ? 0 : ivChartLabelyOffset[s]),
i18next.t(getStatKey(s)),
TextStyle.TOOLTIP_CONTENT
);
statLabel.setOrigin(0.5);
this.ivStatValueTexts[s] = addBBCodeTextObject(this.scene, statLabel.x, statLabel.y + 8, "0", TextStyle.TOOLTIP_CONTENT);
this.ivStatValueTexts[s] = addBBCodeTextObject(this.scene, statLabel.x - (this.showDiff ? 0 : ivLabelOffset[s]), statLabel.y + 8, "0", TextStyle.TOOLTIP_CONTENT);
this.ivStatValueTexts[s].setOrigin(0.5);
this.add(statLabel);
this.add(this.ivStatValueTexts[s]);
}

View File

@ -214,7 +214,7 @@ export default class SummaryUiHandler extends UiHandler {
this.statusContainer.add(statusLabel);
this.status = this.scene.add.sprite(91, 4, "statuses");
this.status = this.scene.add.sprite(91, 4, Utils.getLocalizedSpriteKey("statuses"));
this.status.setOrigin(0.5, 0);
this.statusContainer.add(this.status);
@ -824,6 +824,7 @@ export default class SummaryUiHandler extends UiHandler {
metFragment: i18next.t(`pokemonSummary:metFragment.${this.pokemon?.metBiome === -1? "apparently": "normal"}`, {
biome: `${getBBCodeFrag(getBiomeName(this.pokemon?.metBiome!), TextStyle.SUMMARY_RED)}${closeFragment}`, // TODO: is this bang correct?
level: `${getBBCodeFrag(this.pokemon?.metLevel.toString()!, TextStyle.SUMMARY_RED)}${closeFragment}`, // TODO: is this bang correct?
wave: `${getBBCodeFrag((this.pokemon?.metWave ? this.pokemon.metWave.toString()! : i18next.t("pokemonSummary:unknownTrainer")), TextStyle.SUMMARY_RED)}${closeFragment}`,
}),
natureFragment: i18next.t(`pokemonSummary:natureFragment.${rawNature}`, { nature: nature })
});

View File

@ -1,4 +1,5 @@
import { MoneyFormat } from "#enums/money-format";
import { Moves } from "#enums/moves";
import i18next from "i18next";
export const MissingTextureKey = "__MISSING";
@ -628,3 +629,12 @@ export function getLocalizedSpriteKey(baseKey: string) {
export function isBetween(num: number, min: number, max: number): boolean {
return num >= min && num <= max;
}
/**
* Helper method to return the animation filename for a given move
*
* @param move the move for which the animation filename is needed
*/
export function animationFileName(move: Moves): string {
return Moves[move].toLowerCase().replace(/\_/g, "-");
}

View File

@ -31,6 +31,7 @@ export default defineConfig(({mode}) => {
return ({
...defaultConfig,
base: '',
esbuild: {
pure: mode === 'production' ? ['console.log'] : [],
keepNames: true,