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 Sword/Shield
- Pokémon Legends: Arceus - Pokémon Legends: Arceus
- Pokémon Scarlet/Violet - 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) - Lmz (Custom Jungle biome music)
- Andr06 (Custom Slum and Sea biome music) - Andr06 (Custom Slum and Sea biome music)

View File

@ -26,10 +26,36 @@ body {
#app { #app {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center;
} }
#app > div:first-child { #app > div:first-child {
transform-origin: top !important; transform-origin: center !important;
}
/*
Supports automatic vertical centering as suggested in PR#1114, but only via CSS
Condition factorized to deduce CSS rules:
true if (isLandscape && !isMobile() && !hasTouchscreen() || (hasTouchscreen() && !isTouchControlsEnabled))
*/
/* isLandscape && !isMobile() && !hasTouchscreen() */
@media (orientation: landscape) and (pointer: fine) {
#app {
align-items: center;
}
}
@media (pointer: coarse) {
/* hasTouchscreen() && !isTouchControlsEnabled */
body:has(> #touchControls[class=visible]) #app {
align-items: start;
}
body:has(> #touchControls[class=visible]) #app > div:first-child {
transform-origin: top !important;
}
} }
#layout:fullscreen #dpad, #layout:fullscreen { #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, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -115,7 +115,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -215,7 +215,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -315,7 +315,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -414,7 +414,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -538,7 +538,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 23, "x": 23,
@ -685,7 +685,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -19, "x": -19,
@ -784,7 +784,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 26, "x": 26,
@ -883,7 +883,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 23.5, "x": 23.5,
@ -994,7 +994,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 9, "x": 9,
@ -1069,7 +1069,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -18.5, "x": -18.5,
@ -1157,7 +1157,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 37.5, "x": 37.5,
@ -1221,7 +1221,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1284,7 +1284,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1348,7 +1348,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1448,7 +1448,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1548,7 +1548,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1647,7 +1647,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 0, "x": 0,
@ -1759,7 +1759,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -25.5, "x": -25.5,
@ -1870,7 +1870,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 12, "x": 12,
@ -1957,7 +1957,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -27, "x": -27,
@ -2044,7 +2044,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -16, "x": -16,
@ -2143,7 +2143,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -26.5, "x": -26.5,
@ -2230,7 +2230,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 23, "x": 23,
@ -2306,7 +2306,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": 24, "x": 24,
@ -2346,7 +2346,7 @@
"opacity": 255, "opacity": 255,
"locked": true, "locked": true,
"priority": 1, "priority": 1,
"focus": 2 "focus": 1
}, },
{ {
"x": -27, "x": -27,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,440 +1,230 @@
{ {
"textures": [ "textures": [
{ {
"image": "745.png", "image": "745.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 300, "w": 181,
"h": 300 "h": 181
}, },
"scale": 1, "scale": 1,
"frames": [ "frames": [
{ {
"filename": "0005.png", "filename": "0004.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 1,
"y": 4, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 61
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 0, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 61
} }
}, },
{ {
"filename": "0006.png", "filename": "0008.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 1,
"y": 4, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 61
}, },
"frame": { "frame": {
"x": 60, "x": 0,
"y": 0, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 61
} }
}, },
{ {
"filename": "0015.png", "filename": "0005.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 1,
"y": 4, "y": 1,
"w": 60, "w": 71,
"h": 67 "h": 60
}, },
"frame": { "frame": {
"x": 120, "x": 71,
"y": 0, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 60
} }
}, },
{ {
"filename": "0016.png", "filename": "0007.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 1,
"y": 4, "y": 1,
"w": 60, "w": 71,
"h": 67 "h": 60
}, },
"frame": { "frame": {
"x": 180, "x": 71,
"y": 0, "y": 0,
"w": 60, "w": 71,
"h": 67 "h": 60
} }
}, },
{ {
"filename": "0004.png", "filename": "0006.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 1,
"y": 3, "y": 2,
"w": 60, "w": 71,
"h": 68 "h": 59
}, },
"frame": { "frame": {
"x": 240, "x": 71,
"y": 0, "y": 60,
"w": 60, "w": 71,
"h": 68 "h": 59
} }
}, },
{ {
"filename": "0008.png", "filename": "0003.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 0, "x": 0,
"y": 3, "y": 0,
"w": 61, "w": 70,
"h": 68 "h": 61
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 67, "y": 61,
"w": 61, "w": 70,
"h": 68 "h": 61
} }
}, },
{ {
"filename": "0014.png", "filename": "0009.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 0,
"y": 3, "y": 0,
"w": 60, "w": 70,
"h": 68 "h": 61
}, },
"frame": { "frame": {
"x": 61, "x": 0,
"y": 67, "y": 61,
"w": 60, "w": 70,
"h": 68 "h": 61
} }
}, },
{ {
"filename": "0018.png", "filename": "0001.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 0, "x": 1,
"y": 3, "y": 2,
"w": 61, "w": 68,
"h": 68 "h": 59
}, },
"frame": { "frame": {
"x": 121, "x": 0,
"y": 67, "y": 122,
"w": 61, "w": 68,
"h": 68 "h": 59
} }
}, },
{ {
"filename": "0007.png", "filename": "0002.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 0,
"y": 2, "y": 0,
"w": 60, "w": 69,
"h": 69 "h": 61
}, },
"frame": { "frame": {
"x": 182, "x": 70,
"y": 68, "y": 119,
"w": 60, "w": 69,
"h": 69 "h": 61
} }
}, },
{ {
"filename": "0017.png", "filename": "0010.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 61, "w": 72,
"h": 71 "h": 61
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 0,
"y": 2, "y": 0,
"w": 60, "w": 69,
"h": 69 "h": 61
}, },
"frame": { "frame": {
"x": 0, "x": 70,
"y": 135, "y": 119,
"w": 60, "w": 69,
"h": 69 "h": 61
} }
}, }
{ ]
"filename": "0003.png", }
"rotated": false, ],
"trimmed": true, "meta": {
"sourceSize": { "app": "https://www.codeandweb.com/texturepacker",
"w": 61, "version": "3.0",
"h": 71 "smartupdate": "$TexturePacker:SmartUpdate:9bdd7250af45db121574c90e718874a8:ca85d052f16849220d83acd876b20b8b:f9304907e03a5223c5bc78c934419106$"
}, }
"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
},
"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
},
"frame": {
"x": 0,
"y": 205,
"w": 61,
"h": 71
}
},
{
"filename": "0009.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 61,
"y": 205,
"w": 61,
"h": 71
}
},
{
"filename": "0019.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 61,
"h": 71
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 61,
"h": 71
},
"frame": {
"x": 61,
"y": 205,
"w": 61,
"h": 71
}
},
{
"filename": "0010.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": "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
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:8d47c2cedd75d15c81c3aa0a0b14133c:28c19026319cfbbb59916e3d1b92f732:f9304907e03a5223c5bc78c934419106$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,167 +1,524 @@
{ {
"textures": [ "textures": [
{ {
"image": "745.png", "image": "745.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "size": {
"w": 189, "w": 286,
"h": 189 "h": 286
}, },
"scale": 1, "scale": 1,
"frames": [ "frames": [
{ {
"filename": "0006.png", "filename": "0007.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 0,
"y": 0, "y": 3,
"w": 65, "w": 60,
"h": 58 "h": 55
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 0, "y": 0,
"w": 65, "w": 60,
"h": 58 "h": 55
} }
}, },
{ {
"filename": "0005.png", "filename": "0008.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 0, "x": 0,
"y": 1, "y": 3,
"w": 66, "w": 60,
"h": 57 "h": 55
}, },
"frame": { "frame": {
"x": 65, "x": 60,
"y": 0, "y": 0,
"w": 66, "w": 60,
"h": 57 "h": 55
} }
}, },
{ {
"filename": "0007.png", "filename": "0019.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 2, "x": 0,
"y": 0, "y": 3,
"w": 64, "w": 60,
"h": 58 "h": 55
}, },
"frame": { "frame": {
"x": 65, "x": 120,
"y": 57, "y": 0,
"w": 64, "w": 60,
"h": 58 "h": 55
} }
}, },
{ {
"filename": "0003.png", "filename": "0020.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 2, "x": 0,
"y": 1, "y": 3,
"w": 64, "w": 60,
"h": 57 "h": 55
}, },
"frame": { "frame": {
"x": 0, "x": 180,
"y": 58, "y": 0,
"w": 64, "w": 60,
"h": 57 "h": 55
} }
}, },
{ {
"filename": "0004.png", "filename": "0005.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 1, "x": 0,
"y": 2, "y": 1,
"w": 65, "w": 60,
"h": 56 "h": 57
}, },
"frame": { "frame": {
"x": 0, "x": 0,
"y": 115, "y": 55,
"w": 65, "w": 60,
"h": 56 "h": 57
} }
}, },
{ {
"filename": "0001.png", "filename": "0006.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 3, "x": 0,
"y": 0, "y": 1,
"w": 62, "w": 60,
"h": 58 "h": 57
}, },
"frame": { "frame": {
"x": 65, "x": 60,
"y": 115, "y": 55,
"w": 62, "w": 60,
"h": 58 "h": 57
} }
}, },
{ {
"filename": "0002.png", "filename": "0009.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {
"w": 66, "w": 60,
"h": 58 "h": 58
}, },
"spriteSourceSize": { "spriteSourceSize": {
"x": 3, "x": 0,
"y": 0, "y": 1,
"w": 62, "w": 60,
"h": 58 "h": 57
}, },
"frame": { "frame": {
"x": 127, "x": 120,
"y": 115, "y": 55,
"w": 62, "w": 60,
"h": 58 "h": 57
} }
} },
] {
} "filename": "0010.png",
], "rotated": false,
"meta": { "trimmed": true,
"app": "https://www.codeandweb.com/texturepacker", "sourceSize": {
"version": "3.0", "w": 60,
"smartupdate": "$TexturePacker:SmartUpdate:1b95a218abc87c12576165b943d3cb77:4d796dc75302ca2e18ce15e67dcf3f0f:f9304907e03a5223c5bc78c934419106$" "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": 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": 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": "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": 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": "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
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"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 { export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
/** {@linkcode BattleStat} to protect or `undefined` if **all** {@linkcode BattleStat} are protected */
private protectedStat?: BattleStat; private protectedStat?: BattleStat;
constructor(protectedStat?: BattleStat) { constructor(protectedStat?: BattleStat) {
@ -2634,7 +2638,17 @@ export class ProtectStatAbAttr extends PreStatStageChangeAbAttr {
this.protectedStat = protectedStat; 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) { if (Utils.isNullOrUndefined(this.protectedStat) || stat === this.protectedStat) {
cancelled.value = true; cancelled.value = true;
return true; return true;
@ -3757,7 +3771,7 @@ export class StatStageChangeMultiplierAbAttr extends AbAttr {
this.multiplier = multiplier; 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; (args[0] as Utils.IntegerHolder).value *= this.multiplier;
return true; return true;

View File

@ -488,14 +488,14 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else { } else {
moveAnims.set(move, null); moveAnims.set(move, null);
const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP; 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) => { const fetchAnimAndResolve = (move: Moves) => {
scene.cachedFetch(`./battle-anims/${moveName}.json`) scene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`)
.then(response => { .then(response => {
const contentType = response.headers.get("content-type"); const contentType = response.headers.get("content-type");
if (!response.ok || contentType?.indexOf("application/json") === -1) { if (!response.ok || contentType?.indexOf("application/json") === -1) {
console.error(`Could not load animation file for move '${moveName}'`, response.status, response.statusText); useDefaultAnim(move, defaultMoveAnim);
populateMoveAnim(move, moveAnims.get(defaultMoveAnim)); logMissingMoveAnim(move, response.status, response.statusText);
return resolve(); return resolve();
} }
return response.json(); return response.json();
@ -515,6 +515,11 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else { } else {
resolve(); resolve();
} }
})
.catch(error => {
useDefaultAnim(move, defaultMoveAnim);
logMissingMoveAnim(move, error);
return resolve();
}); });
}; };
fetchAnimAndResolve(move); 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 * Fetches animation configs to be used in a Mystery Encounter
* @param scene * @param scene

View File

@ -3839,7 +3839,7 @@ export class StormAccuracyAttr extends VariableAccuracyAttr {
* @extends VariableAccuracyAttr * @extends VariableAccuracyAttr
* @see {@linkcode apply} * @see {@linkcode apply}
*/ */
export class MinimizeAccuracyAttr extends VariableAccuracyAttr { export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr {
/** /**
* @see {@linkcode apply} * @see {@linkcode apply}
* @param user N/A * @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 * Attribute used when a move hits a {@linkcode BattlerTagType} for double damage
* @extends MoveAttr * @extends MoveAttr
*/ */
export class HitsTagAttr extends MoveAttr { export class DealsDoubleDamageToTagAttr extends MoveAttr {
/** The {@linkcode BattlerTagType} this move hits */ /** The {@linkcode BattlerTagType} this move hits */
public tagType: BattlerTagType; 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; public doubleDamage: boolean;
constructor(tagType: BattlerTagType, 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) new AttackMove(Moves.CUT, Type.NORMAL, MoveCategory.PHYSICAL, 50, 95, 30, -1, 0, 1)
.slicingMove(), .slicingMove(),
new AttackMove(Moves.GUST, Type.FLYING, MoveCategory.SPECIAL, 40, 100, 35, -1, 0, 1) 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(), .windMove(),
new AttackMove(Moves.WING_ATTACK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, 0, 1), 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) new StatusMove(Moves.WHIRLWIND, Type.NORMAL, -1, 20, -1, -6, 1)
.attr(ForceSwitchOutAttr) .attr(ForceSwitchOutAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
.ignoresSubstitute() .ignoresSubstitute()
.hidesTarget() .hidesTarget()
.windMove(), .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.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.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) new AttackMove(Moves.STOMP, Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 1)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr), .attr(FlinchAttr),
new AttackMove(Moves.DOUBLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, 0, 1) new AttackMove(Moves.DOUBLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, 0, 1)
.attr(MultiHitAttr, MultiHitType._2), .attr(MultiHitAttr, MultiHitType._2),
@ -6795,8 +6794,8 @@ export function initMoves() {
.attr(OneHitKOAccuracyAttr), .attr(OneHitKOAccuracyAttr),
new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1), 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) new AttackMove(Moves.BODY_SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 30, 0, 1)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS), .attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1) new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1)
.attr(TrapAttr, BattlerTagType.WRAP), .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.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) new AttackMove(Moves.SURF, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 1)
.target(MoveTarget.ALL_NEAR_OTHERS) .target(MoveTarget.ALL_NEAR_OTHERS)
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERWATER, true)
.attr(GulpMissileTagAttr), .attr(GulpMissileTagAttr),
new AttackMove(Moves.ICE_BEAM, Type.ICE, MoveCategory.SPECIAL, 90, 100, 10, 10, 0, 1) new AttackMove(Moves.ICE_BEAM, Type.ICE, MoveCategory.SPECIAL, 90, 100, 10, 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.FREEZE), .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) new AttackMove(Moves.THUNDER, Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 1)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS) .attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.attr(ThunderAccuracyAttr) .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) new AttackMove(Moves.ROCK_THROW, Type.ROCK, MoveCategory.PHYSICAL, 50, 90, 15, -1, 0, 1)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.EARTHQUAKE, Type.GROUND, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 1) new AttackMove(Moves.EARTHQUAKE, Type.GROUND, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 1)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
.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) .makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS), .target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1) new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
.attr(OneHitKOAttr) .attr(OneHitKOAttr)
.attr(OneHitKOAccuracyAttr) .attr(OneHitKOAccuracyAttr)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, false)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.DIG, Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 1) 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) .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) new AttackMove(Moves.MAGNITUDE, Type.GROUND, MoveCategory.PHYSICAL, -1, 100, 30, -1, 0, 2)
.attr(PreMoveMessageAttr, magnitudeMessageFunc) .attr(PreMoveMessageAttr, magnitudeMessageFunc)
.attr(MagnitudePowerAttr) .attr(MagnitudePowerAttr)
.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)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
.makesContact(false) .makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS), .target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.DYNAMIC_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 50, 5, 100, 0, 2) 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) new AttackMove(Moves.CROSS_CHOP, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, -1, 0, 2)
.attr(HighCritAttr), .attr(HighCritAttr),
new AttackMove(Moves.TWISTER, Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, 20, 0, 2) 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) .attr(FlinchAttr)
.windMove() .windMove()
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
@ -7435,7 +7434,7 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.DEF ], -1), .attr(StatStageChangeAttr, [ Stat.DEF ], -1),
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2) new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2)
.attr(TrapAttr, BattlerTagType.WHIRLPOOL) .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) new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
.attr(MultiHitAttr, MultiHitType.BEAT_UP) .attr(MultiHitAttr, MultiHitType.BEAT_UP)
.attr(BeatUpAttr) .attr(BeatUpAttr)
@ -7658,7 +7657,7 @@ export function initMoves() {
new AttackMove(Moves.EXTRASENSORY, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, 10, 0, 3) new AttackMove(Moves.EXTRASENSORY, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, 10, 0, 3)
.attr(FlinchAttr), .attr(FlinchAttr),
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3) new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
.attr(HitsTagAttr, BattlerTagType.FLYING) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING)
.punchingMove(), .punchingMove(),
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3) new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3)
.attr(TrapAttr, BattlerTagType.SAND_TOMB) .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) new AttackMove(Moves.DRAGON_PULSE, Type.DRAGON, MoveCategory.SPECIAL, 85, 100, 10, -1, 0, 4)
.pulseMove(), .pulseMove(),
new AttackMove(Moves.DRAGON_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, 20, 0, 4) new AttackMove(Moves.DRAGON_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, 20, 0, 4)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr), .attr(FlinchAttr),
new AttackMove(Moves.POWER_GEM, Type.ROCK, MoveCategory.SPECIAL, 80, 100, 20, -1, 0, 4), 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) 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.IGNORE_FLYING, false, false, 1, 1, true)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN]) .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.attr(HitsTagAttr, BattlerTagType.FLYING, false) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5) new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
.attr(CritOnlyAttr), .attr(CritOnlyAttr),
@ -8100,9 +8099,9 @@ export function initMoves() {
.attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true) .attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true)
.danceMove(), .danceMove(),
new AttackMove(Moves.HEAVY_SLAM, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5) new AttackMove(Moves.HEAVY_SLAM, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(CompareWeightPowerAttr) .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) new AttackMove(Moves.SYNCHRONOISE, Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 5)
.target(MoveTarget.ALL_NEAR_OTHERS) .target(MoveTarget.ALL_NEAR_OTHERS)
.condition(unknownTypeCondition) .condition(unknownTypeCondition)
@ -8221,7 +8220,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BULLDOZE, Type.GROUND, MoveCategory.PHYSICAL, 60, 100, 20, 100, 0, 5) new AttackMove(Moves.BULLDOZE, Type.GROUND, MoveCategory.PHYSICAL, 60, 100, 20, 100, 0, 5)
.attr(StatStageChangeAttr, [ Stat.SPD ], -1) .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) .makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS), .target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FROST_BREATH, Type.ICE, MoveCategory.SPECIAL, 60, 90, 10, 100, 0, 5) 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) .attr(StatStageChangeAttr, [ Stat.DEF ], -1)
.slicingMove(), .slicingMove(),
new AttackMove(Moves.HEAT_CRASH, Type.FIRE, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5) new AttackMove(Moves.HEAT_CRASH, Type.FIRE, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(CompareWeightPowerAttr) .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) new AttackMove(Moves.LEAF_TORNADO, Type.GRASS, MoveCategory.SPECIAL, 65, 90, 10, 50, 0, 5)
.attr(StatStageChangeAttr, [ Stat.ACC ], -1), .attr(StatStageChangeAttr, [ Stat.ACC ], -1),
new AttackMove(Moves.STEAMROLLER, Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 5) new AttackMove(Moves.STEAMROLLER, Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 5)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.attr(FlinchAttr), .attr(FlinchAttr),
new SelfStatusMove(Moves.COTTON_GUARD, Type.GRASS, -1, 10, -1, 0, 5) new SelfStatusMove(Moves.COTTON_GUARD, Type.GRASS, -1, 10, -1, 0, 5)
.attr(StatStageChangeAttr, [ Stat.DEF ], 3, true), .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) new AttackMove(Moves.HURRICANE, Type.FLYING, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 5)
.attr(ThunderAccuracyAttr) .attr(ThunderAccuracyAttr)
.attr(ConfuseAttr) .attr(ConfuseAttr)
.attr(HitsTagAttr, BattlerTagType.FLYING, false) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.windMove(), .windMove(),
new AttackMove(Moves.HEAD_CHARGE, Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 5) new AttackMove(Moves.HEAD_CHARGE, Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 5)
.attr(RecoilAttr) .attr(RecoilAttr)
@ -8325,9 +8326,9 @@ export function initMoves() {
.attr(LastMoveDoublePowerAttr, Moves.FUSION_FLARE) .attr(LastMoveDoublePowerAttr, Moves.FUSION_FLARE)
.makesContact(false), .makesContact(false),
new AttackMove(Moves.FLYING_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, 0, 6) new AttackMove(Moves.FLYING_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, 0, 6)
.attr(MinimizeAccuracyAttr) .attr(AlwaysHitMinimizeAttr)
.attr(FlyingTypeMultiplierAttr) .attr(FlyingTypeMultiplierAttr)
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.condition(failOnGravityCondition), .condition(failOnGravityCondition),
new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6) new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6)
.target(MoveTarget.USER_SIDE) .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) new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr) .attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true) .attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
.attr(HitsTagAttr, BattlerTagType.FLYING, false) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
.attr(HitsTagAttr, BattlerTagType.MAGNET_RISEN, false) .attr(DealsDoubleDamageToTagAttr, BattlerTagType.MAGNET_RISEN, false)
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN]) .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
.makesContact(false) .makesContact(false)
@ -8756,6 +8757,8 @@ export function initMoves() {
.partial() .partial()
.ignoresVirtual(), .ignoresVirtual(),
new AttackMove(Moves.MALICIOUS_MOONSAULT, Type.DARK, MoveCategory.PHYSICAL, 180, -1, 1, -1, 0, 7) new AttackMove(Moves.MALICIOUS_MOONSAULT, Type.DARK, MoveCategory.PHYSICAL, 180, -1, 1, -1, 0, 7)
.attr(AlwaysHitMinimizeAttr)
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
.partial() .partial()
.ignoresVirtual(), .ignoresVirtual(),
new AttackMove(Moves.OCEANIC_OPERETTA, Type.WATER, MoveCategory.SPECIAL, 195, -1, 1, -1, 0, 7) 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)) new SpeciesFormChange(Species.GROUDON, "", SpeciesFormKey.PRIMAL, new SpeciesFormChangeItemTrigger(FormChangeItem.RED_ORB))
], ],
[Species.RAYQUAZA]: [ [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]: [ [Species.DEOXYS]: [
new SpeciesFormChange(Species.DEOXYS, "normal", "attack", new SpeciesFormChangeItemTrigger(FormChangeItem.SHARP_METEORITE)), new SpeciesFormChange(Species.DEOXYS, "normal", "attack", new SpeciesFormChangeItemTrigger(FormChangeItem.SHARP_METEORITE)),

View File

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

View File

@ -3,7 +3,7 @@ import BattleScene, { AnySound } from "../battle-scene";
import { Variant, VariantSet, variantColorCache } from "#app/data/variant"; import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
import { variantData } from "#app/data/variant"; import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info"; 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 { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils"; import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
import * as Utils from "../utils"; import * as Utils from "../utils";
@ -95,6 +95,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public metLevel: integer; public metLevel: integer;
public metBiome: Biome | -1; public metBiome: Biome | -1;
public metSpecies: Species; public metSpecies: Species;
public metWave: number;
public luck: integer; public luck: integer;
public pauseEvolutions: boolean; public pauseEvolutions: boolean;
public pokerus: boolean; public pokerus: boolean;
@ -194,6 +195,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.luck = dataSource.luck; this.luck = dataSource.luck;
this.metBiome = dataSource.metBiome; this.metBiome = dataSource.metBiome;
this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true)); this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true));
this.metWave = dataSource.metWave ?? (this.metBiome === -1 ? -1 : 0);
this.pauseEvolutions = dataSource.pauseEvolutions; this.pauseEvolutions = dataSource.pauseEvolutions;
this.pokerus = !!dataSource.pokerus; this.pokerus = !!dataSource.pokerus;
this.evoCounter = dataSource.evoCounter ?? 0; this.evoCounter = dataSource.evoCounter ?? 0;
@ -240,6 +242,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.metLevel = level; this.metLevel = level;
this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1; this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1;
this.metSpecies = species.speciesId; this.metSpecies = species.speciesId;
this.metWave = scene.currentBattle ? scene.currentBattle.waveIndex : -1;
this.pokerus = false; this.pokerus = false;
if (level > 1) { 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 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 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 * @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[] { getAbilityAttrs<T extends AbAttr = AbAttr>(attrType: { new(...args: any[]): T }, canApply: boolean = true, ignoreOverride?: boolean): T[] {
const abilityAttrs: AbAttr[] = []; const abilityAttrs: T[] = [];
if (!canApply || this.canApplyAbility()) { if (!canApply || this.canApplyAbility()) {
abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs(attrType)); abilityAttrs.push(...this.getAbility(ignoreOverride).getAttrs<T>(attrType));
} }
if (!canApply || this.canApplyAbility(true)) { 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); const immuneTags = this.findTags(tag => tag instanceof TypeImmuneTag && tag.immuneType === moveType);
for (const tag of immuneTags) { 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; typeMultiplier.value = 0;
break; 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); 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 * The target has a {@linkcode BattlerTagType} that this move interacts with
* AND * AND
* The move doubles damage when used against that tag * The move doubles damage when used against that tag
*/ */
const hitsTagMultiplier = new Utils.NumberHolder(1); 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)) { if (this.getTag(hta.tagType)) {
hitsTagMultiplier.value *= 2; hitsTagMultiplier.value *= 2;
} }
@ -4081,6 +4084,7 @@ export class PlayerPokemon extends Pokemon {
newPokemon.metLevel = this.metLevel; newPokemon.metLevel = this.metLevel;
newPokemon.metBiome = this.metBiome; newPokemon.metBiome = this.metBiome;
newPokemon.metSpecies = this.metSpecies; newPokemon.metSpecies = this.metSpecies;
newPokemon.metWave = this.metWave;
newPokemon.fusionSpecies = this.fusionSpecies; newPokemon.fusionSpecies = this.fusionSpecies;
newPokemon.fusionFormIndex = this.fusionFormIndex; newPokemon.fusionFormIndex = this.fusionFormIndex;
newPokemon.fusionAbilityIndex = this.fusionAbilityIndex; newPokemon.fusionAbilityIndex = this.fusionAbilityIndex;
@ -4088,6 +4092,7 @@ export class PlayerPokemon extends Pokemon {
newPokemon.fusionVariant = this.fusionVariant; newPokemon.fusionVariant = this.fusionVariant;
newPokemon.fusionGender = this.fusionGender; newPokemon.fusionGender = this.fusionGender;
newPokemon.fusionLuck = this.fusionLuck; newPokemon.fusionLuck = this.fusionLuck;
newPokemon.usedTMs = this.usedTMs;
this.scene.getParty().push(newPokemon); this.scene.getParty().push(newPokemon);
newPokemon.evolve((!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution)), evoSpecies); newPokemon.evolve((!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution)), evoSpecies);
@ -4779,6 +4784,7 @@ export class EnemyPokemon extends Pokemon {
this.pokeball = pokeballType; this.pokeball = pokeballType;
this.metLevel = this.level; this.metLevel = this.level;
this.metBiome = this.scene.arena.biomeType; this.metBiome = this.scene.arena.biomeType;
this.metWave = this.scene.currentBattle.waveIndex;
this.metSpecies = this.species.speciesId; 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); 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; const lang = i18next.resolvedLanguage;
if (lang !== "en") { if (lang !== "en") {
if (Utils.verifyLang(lang)) { if (Utils.verifyLang(lang)) {
this.loadAtlas(`statuses_${lang}`, "");
this.loadAtlas(`types_${lang}`, ""); this.loadAtlas(`types_${lang}`, "");
} else { } else {
// Fallback to English // Fallback to English
this.loadAtlas("statuses", "");
this.loadAtlas("types", ""); this.loadAtlas("types", "");
} }
} else { } else {
this.loadAtlas("statuses", "");
this.loadAtlas("types", ""); this.loadAtlas("types", "");
} }
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"]; const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"];

View File

@ -11,7 +11,7 @@
"cancel": "Abbrechen", "cancel": "Abbrechen",
"memoString": "Wesen: {{natureFragment}}\n{{metFragment}}", "memoString": "Wesen: {{natureFragment}}\n{{metFragment}}",
"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." "apparently": "Herkunft: {{biome}}\nOffenbar mit Lv. {{level}} erhalten."
}, },
"natureFragment": { "natureFragment": {

View File

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

View File

@ -6,8 +6,8 @@
"option": { "option": {
"1": { "1": {
"label": "Dig for Valuables", "label": "Dig for Valuables",
"tooltip": "(-) Lose Healing Items in Shops\n(+) Gain Amazing Items", "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 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!" "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": { "2": {
"label": "Investigate Further", "label": "Investigate Further",

View File

@ -11,7 +11,7 @@
"cancel": "Cancel", "cancel": "Cancel",
"memoString": "{{natureFragment}} nature,\n{{metFragment}}", "memoString": "{{natureFragment}} nature,\n{{metFragment}}",
"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}}." "apparently": "apparently met at Lv{{level}},\n{{biome}}."
}, },
"natureFragment": { "natureFragment": {

View File

@ -11,7 +11,7 @@
"cancel": "Salir", "cancel": "Salir",
"memoString": "Naturaleza {{natureFragment}},\n{{metFragment}}", "memoString": "Naturaleza {{natureFragment}},\n{{metFragment}}",
"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}}." "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é.", "moveNotImplemented": "{{moveName}} nest pas encore implémenté et ne peut pas être sélectionné.",
"moveNoPP": "Il ny a plus de PP pour\ncette capacité !", "moveNoPP": "Il ny a plus de PP pour\ncette capacité !",
"moveDisabled": "{{moveName}} est sous entrave !", "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}} !", "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.", "noPokeballForce": "Une force mystérieuse\nempêche lutilisation des Poké Balls.",
"noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, cest mal !", "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, cest mal !",
"noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon !", "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon !",

View File

@ -46,7 +46,7 @@
"yes": "Oui", "yes": "Oui",
"no": "Non", "no": "Non",
"disclaimer": "AVERTISSEMENT", "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.", "choosePokemon": "Sélectionnez un Pokémon.",
"renamePokemon": "Renommer le Pokémon", "renamePokemon": "Renommer le Pokémon",
"rename": "Renommer", "rename": "Renommer",

View File

@ -7,6 +7,7 @@
"switchedStat": "{{pokemonName}} et sa cible échangent leur {{stat}} !", "switchedStat": "{{pokemonName}} et sa cible échangent leur {{stat}} !",
"sharedGuard": "{{pokemonName}} additionne sa garde à celle de sa cible et redistribue le tout équitablement !", "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 !", "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 !", "goingAllOutForAttack": "{{pokemonName}} a pris\ncette capacité au sérieux !",
"regainedHealth": "{{pokemonName}}\nrécupère des PV !", "regainedHealth": "{{pokemonName}}\nrécupère des PV !",
"keptGoingAndCrashed": "{{pokemonName}}\nsécrase au sol !", "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}} !", "swapArenaTags": "Les effets affectant chaque côté du terrain\nont été échangés par {{pokemonName}} !",
"exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !", "exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !",
"safeguard": "{{targetName}} est protégé\npar la capacité Rune Protect !", "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 !" "afterYou": "{{pokemonName}} accepte\navec joie !"
} }

View File

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

View File

@ -11,7 +11,7 @@
"cancel": "Annuler", "cancel": "Annuler",
"memoString": "{{natureFragment}} de nature,\n{{metFragment}}", "memoString": "{{natureFragment}} de nature,\n{{metFragment}}",
"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}}." "apparently": "apparemment rencontré au N.{{level}},\n{{biome}}."
}, },
"natureFragment": { "natureFragment": {

View File

@ -94,7 +94,7 @@
"caitlin": "Percila", "caitlin": "Percila",
"malva": "Malva", "malva": "Malva",
"siebold": "Narcisse", "siebold": "Narcisse",
"wikstrom": "Tileo", "wikstrom": "Thyméo",
"drasna": "Dracéna", "drasna": "Dracéna",
"hala": "Pectorius", "hala": "Pectorius",
"molayne": "Molène", "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é !", "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.", "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.", "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", "cancel": "Annulla",
"memoString": "Natura {{natureFragment}},\n{{metFragment}}", "memoString": "Natura {{natureFragment}},\n{{metFragment}}",
"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}}." "apparently": "apparentemente incontrato al Lv.{{level}},\n{{biome}}."
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
"cancel": "Cancelar", "cancel": "Cancelar",
"memoString": "Natureza {{natureFragment}},\n{{metFragment}}", "memoString": "Natureza {{natureFragment}},\n{{metFragment}}",
"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}}." "apparently": "aparentemente encontrado no Nv.{{level}},\n{{biome}}."
}, },
"natureFragment": { "natureFragment": {

View File

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

View File

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

View File

@ -216,8 +216,8 @@ export class EncounterPhase extends BattlePhase {
this.scene.ui.setMode(Mode.MESSAGE).then(() => { this.scene.ui.setMode(Mode.MESSAGE).then(() => {
if (!this.loaded) { if (!this.loaded) {
//@ts-ignore this.trySetWeatherIfNewBiome(); // Set weather before session gets saved
this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || (this.scene.lastSavePlayTime ?? 0) >= 300).then(success => {
this.scene.disableMenu = false; this.scene.disableMenu = false;
if (!success) { if (!success) {
return this.scene.reset(true); 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(); const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({ this.scene.tweens.add({
targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(), 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; 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 { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag";
import { MoveAnim } from "#app/data/battle-anims"; import { MoveAnim } from "#app/data/battle-anims";
import { BattlerTagLapseType, DamageProtectedTag, ProtectedTag, SemiInvulnerableTag, SubstituteTag } from "#app/data/battler-tags"; 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 { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms";
import { BattlerTagType } from "#app/enums/battler-tag-type"; import { BattlerTagType } from "#app/enums/battler-tag-type";
import { Moves } from "#app/enums/moves"; import { Moves } from "#app/enums/moves";
@ -394,7 +394,7 @@ export class MoveEffectPhase extends PokemonPhase {
} }
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); 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; 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())) { for (const pokemon of this.scene.getParty().filter(p => p.isOnField())) {
applyAbAttrs(PostBiomeChangeAbAttr, pokemon, null); 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 { getPokemonNameWithAffix } from "#app/messages";
import { ResetNegativeStatStageModifier } from "#app/modifier/modifier"; import { ResetNegativeStatStageModifier } from "#app/modifier/modifier";
import { handleTutorial, Tutorial } from "#app/tutorial"; import { handleTutorial, Tutorial } from "#app/tutorial";
import * as Utils from "#app/utils"; import { NumberHolder, BooleanHolder } from "#app/utils";
import i18next from "i18next"; import i18next from "i18next";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat"; import { Stat, type BattleStat, getStatKey, getStatStageChangeDescriptionKey } from "#enums/stat";
@ -42,17 +42,23 @@ export class StatStageChangePhase extends PokemonPhase {
return this.end(); return this.end();
} }
const stages = new NumberHolder(this.stages);
if (!this.ignoreAbilities) {
applyAbAttrs(StatStageChangeMultiplierAbAttr, pokemon, null, false, stages);
}
let simulate = false; let simulate = false;
const filteredStats = this.stats.filter(stat => { 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 // TODO: Include simulate boolean when tag applications can be simulated
this.scene.arena.applyTagsForSide(MistTag, pokemon.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, cancelled); 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); applyPreStatStageChangeAbAttrs(ProtectStatAbAttr, pokemon, stat, cancelled, simulate);
} }
@ -64,12 +70,6 @@ export class StatStageChangePhase extends PokemonPhase {
return !cancelled.value; 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)); 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); this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels);

View File

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

View File

@ -31,7 +31,7 @@ describe("Abilities - Contrary", () => {
}); });
it("should invert stat changes when applied", async() => { it("should invert stat changes when applied", async() => {
await game.startBattle([ await game.classicMode.startBattle([
Species.SLOWBRO Species.SLOWBRO
]); ]);
@ -39,4 +39,39 @@ describe("Abilities - Contrary", () => {
expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1); expect(enemyPokemon.getStatStage(Stat.ATK)).toBe(1);
}, 20000); }, 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 game.override
.battleType("single") .battleType("single")
.disableCrits() .disableCrits()
.enemyLevel(30) .enemyLevel(1)
.enemySpecies(Species.SNORLAX) .enemySpecies(Species.SHUCKLE)
.enemyAbility(Abilities.BALL_FETCH) .enemyAbility(Abilities.STURDY)
.enemyMoveset(Moves.SPLASH) .enemyMoveset(Moves.FLY)
.moveset([Moves.GRASSY_TERRAIN, Moves.EARTHQUAKE]) .moveset([Moves.GRASSY_TERRAIN, Moves.EARTHQUAKE])
.ability(Abilities.BALL_FETCH); .ability(Abilities.NO_GUARD);
}); });
it("halves the damage of Earthquake", async () => { it("halves the damage of Earthquake", async () => {
await game.classicMode.startBattle([Species.FEEBAS]); await game.classicMode.startBattle([Species.TAUROS]);
const eq = allMoves[Moves.EARTHQUAKE]; const eq = allMoves[Moves.EARTHQUAKE];
vi.spyOn(eq, "calculateBattlePower"); vi.spyOn(eq, "calculateBattlePower");
@ -53,4 +53,19 @@ describe("Arena - Grassy Terrain", () => {
expect(eq.calculateBattlePower).toHaveReturnedWith(50); expect(eq.calculateBattlePower).toHaveReturnedWith(50);
}, TIMEOUT); }, 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 { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import Phaser from "phaser"; 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", () => { describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
@ -290,22 +291,27 @@ describe("Test Battle Phase", () => {
expect(game.scene.currentBattle.turn).toBeGreaterThan(turn); expect(game.scene.currentBattle.turn).toBeGreaterThan(turn);
}, 20000); }, 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; const moveToUse = Moves.SPLASH;
game.override.battleType("single"); game.override
game.override.starterSpecies(Species.MEWTWO); .battleType("single")
game.override.enemySpecies(Species.RATTATA); .starterSpecies(Species.MEWTWO)
game.override.enemyAbility(Abilities.HYDRATION); .enemySpecies(Species.RATTATA)
game.override.ability(Abilities.ZEN_MODE); .enemyAbility(Abilities.HYDRATION)
game.override.startingLevel(2000); .ability(Abilities.ZEN_MODE)
game.override.startingWave(3); .startingLevel(2000)
game.override.moveset([moveToUse]); .startingWave(3)
.startingBiome(Biome.LAKE)
.moveset([moveToUse]);
game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]); game.override.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
await game.startBattle(); await game.classicMode.startBattle();
const waveIndex = game.scene.currentBattle.waveIndex; const waveIndex = game.scene.currentBattle.waveIndex;
game.move.select(moveToUse); game.move.select(moveToUse);
vi.spyOn(game.scene.arena, "trySetWeather");
await game.doKillOpponents(); await game.doKillOpponents();
await game.toNextWave(); await game.toNextWave();
expect(game.scene.arena.trySetWeather).not.toHaveBeenCalled();
expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex); expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex);
}, 20000); }, 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 () => { it("should not have RNG inconsistencies after a biome switch", async () => {
game.override game.override
.startingWave(10) .startingWave(10)
.startingBiome(Biome.CAVE) // Will lead to biomes with randomly generated weather
.battleType("single") .battleType("single")
.startingLevel(100) .startingLevel(100) // Avoid levelling up
.enemyLevel(1000) .enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents()
.disableTrainerWaves() .disableTrainerWaves()
.moveset([Moves.KOWTOW_CLEAVE]) .moveset([Moves.KOWTOW_CLEAVE])
.enemyMoveset(Moves.SPLASH); .enemyMoveset(Moves.SPLASH);
await game.dailyMode.startBattle(); 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); game.move.select(Moves.KOWTOW_CLEAVE);
await game.phaseInterceptor.to("DamagePhase"); await game.phaseInterceptor.to("DamagePhase");
await game.doKillOpponents(); await game.doKillOpponents();
@ -63,6 +62,34 @@ describe("Reload", () => {
expect(preReloadRngState).toBe(postReloadRngState); expect(preReloadRngState).toBe(postReloadRngState);
}, 20000); }, 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 () => { it("should not have RNG inconsistencies at a Daily run wild Pokemon fight", async () => {
await game.dailyMode.startBattle(); 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 { Mode } from "#app/ui/ui";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { ExpNotification } from "#enums/exp-notification"; import { ExpNotification } from "#enums/exp-notification";
import { GameDataType } from "#enums/game-data-type";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils"; 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. * @returns A promise that resolves with the exported save data.
*/ */
exportSaveToTest(): Promise<string> { exportSaveToTest(): Promise<string> {
const saveKey = "x0i2O7WRiANTqPmZ";
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
await this.scene.gameData.saveAll(this.scene, true, true, true, true); const sessionSaveData = this.scene.gameData.getSessionSaveData(this.scene);
this.scene.reset(true); const encryptedSaveData = AES.encrypt(JSON.stringify(sessionSaveData), saveKey).toString();
await waitUntil(() => this.scene.ui?.getMode() === Mode.TITLE); resolve(encryptedSaveData);
await this.scene.gameData.tryExportData(GameDataType.SESSION, 0);
await waitUntil(() => localStorage.hasOwnProperty("toExport"));
return resolve(localStorage.getItem("toExport")!); // TODO: is this bang correct?;
}); });
} }

View File

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

View File

@ -1,7 +1,9 @@
import BattleScene from "./battle-scene"; import BattleScene from "./battle-scene";
import AwaitableUiHandler from "./ui/awaitable-ui-handler"; import AwaitableUiHandler from "./ui/awaitable-ui-handler";
import UiHandler from "./ui/ui-handler";
import { Mode } from "./ui/ui"; import { Mode } from "./ui/ui";
import i18next from "i18next"; import i18next from "i18next";
import Overrides from "#app/overrides";
export enum Tutorial { export enum Tutorial {
Intro = "INTRO", Intro = "INTRO",
@ -39,7 +41,7 @@ const tutorialHandlers = {
scene.ui.showText(i18next.t("tutorial:starterSelect"), null, () => scene.ui.showText("", null, () => resolve()), null, true); scene.ui.showText(i18next.t("tutorial:starterSelect"), null, () => scene.ui.showText("", null, () => resolve()), null, true);
}); });
}, },
[Tutorial.Pokerus]: (scene: BattleScene) => { [Tutorial.Pokerus]: (scene: BattleScene) => {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText("", null, () => resolve()), null, true); scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText("", null, () => resolve()), null, true);
}); });
@ -63,26 +65,87 @@ const tutorialHandlers = {
}, },
}; };
export function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise<boolean> { /**
return new Promise<boolean>(resolve => { * Run through the specified tutorial if it hasn't been seen before and mark it as seen once done
if (!scene.enableTutorials) { * This will show a tutorial overlay if defined in the current {@linkcode AwaitableUiHandler}
return resolve(false); * 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]) { if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP) {
return resolve(false); return false;
} }
const handler = scene.ui.getHandler(); const handler = scene.ui.getHandler();
if (handler instanceof AwaitableUiHandler) { const isMenuDisabled = scene.disableMenu;
handler.tutorialActive = true;
} // starting tutorial, disable menu
tutorialHandlers[tutorial](scene).then(() => { scene.disableMenu = true;
scene.gameData.saveTutorialFlag(tutorial, true); if (handler instanceof AwaitableUiHandler) {
if (handler instanceof AwaitableUiHandler) { handler.tutorialActive = true;
handler.tutorialActive = false; }
}
resolve(true); 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;
}
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 awaitingActionInput: boolean;
protected onActionInput: Function | null; protected onActionInput: Function | null;
public tutorialActive: boolean = false; public tutorialActive: boolean = false;
public tutorialOverlay: Phaser.GameObjects.Rectangle;
constructor(scene: BattleScene, mode: Mode | null = null) { constructor(scene: BattleScene, mode: Mode | null = null) {
super(scene, mode); super(scene, mode);
@ -24,4 +25,21 @@ export default abstract class AwaitableUiHandler extends UiHandler {
return false; 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.splicedIcon.setInteractive(new Phaser.Geom.Rectangle(0, 0, 12, 15), Phaser.Geom.Rectangle.Contains);
this.add(this.splicedIcon); 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.setName("icon_status");
this.statusIndicator.setVisible(false); this.statusIndicator.setVisible(false);
this.statusIndicator.setOrigin(0, 0); this.statusIndicator.setOrigin(0, 0);

View File

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

View File

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

View File

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

View File

@ -157,6 +157,9 @@ export default class MenuUiHandler extends MessageUiHandler {
menuMessageText.setOrigin(0, 0); menuMessageText.setOrigin(0, 0);
this.menuMessageBoxContainer.add(menuMessageText); this.menuMessageBoxContainer.add(menuMessageText);
this.initTutorialOverlay(this.menuContainer);
this.initPromptSprite(this.menuMessageBoxContainer);
this.message = menuMessageText; this.message = menuMessageText;
// By default we use the general purpose message window // 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"); 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); handleTutorial(this.scene, Tutorial.Menu);
this.bgmBar.toggleBgmBar(true); this.bgmBar.toggleBgmBar(true);

View File

@ -17,6 +17,23 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
this.pendingPrompt = false; 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) { 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); this.showTextInternal(text, delay, callback, callbackDelay, prompt, promptDelay);
} }
@ -180,7 +197,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const lastLineWidth = lastLineTest.displayWidth; const lastLineWidth = lastLineTest.displayWidth;
lastLineTest.destroy(); lastLineTest.destroy();
if (this.prompt) { 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.prompt.play("prompt");
} }
this.pendingPrompt = false; this.pendingPrompt = false;

View File

@ -91,7 +91,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem
valuesBg.setOrigin(0, 0); valuesBg.setOrigin(0, 0);
this.val.add(valuesBg); 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.typ.setScale(0.8);
this.val.add(this.typ); 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.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---"); this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.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.cat.setFrame(MoveCategory[move.category].toLowerCase());
this.desc.setText(move?.effect || ""); this.desc.setText(move?.effect || "");

View File

@ -1272,7 +1272,7 @@ class PartySlot extends Phaser.GameObjects.Container {
} }
if (this.pokemon.status) { 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.setFrame(StatusEffect[this.pokemon.status?.effect].toLowerCase());
statusIndicator.setOrigin(0, 0); statusIndicator.setOrigin(0, 0);
statusIndicator.setPositionRelative(slotLevelLabel, this.slotIndex >= battlerCount ? 43 : 55, 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.pokemonCaughtHatchedContainer.add(this.pokemonHatchedCountText);
this.pokemonMovesContainer = this.scene.add.container(102, 16); 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++) { for (let m = 0; m < 4; m++) {
const moveContainer = this.scene.add.container(0, 14 * 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.message.setOrigin(0, 0);
this.starterSelectMessageBoxContainer.add(this.message); this.starterSelectMessageBoxContainer.add(this.message);
// arrow icon for the message box
this.initPromptSprite(this.starterSelectMessageBoxContainer);
this.statsContainer = new StatsContainer(this.scene, 6, 16); this.statsContainer = new StatsContainer(this.scene, 6, 16);
this.scene.add.existing(this.statsContainer); 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, y: this.scene.game.canvas.height / 6 - MoveInfoOverlay.getHeight(overlayScale) - 29,
}); });
this.starterSelectContainer.add(this.moveInfoOverlay); this.starterSelectContainer.add(this.moveInfoOverlay);
// Filter bar sits above everything, except the tutorial overlay and message box
this.starterSelectContainer.bringToTop(this.filterBarContainer); 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)); 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 { PERMANENT_STATS, getStatKey } from "#app/enums/stat";
import i18next from "i18next"; import i18next from "i18next";
const ivChartSize = 24; 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 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 speedLabelOffset = -3;
const sideLabelOffset = 1; const sideLabelOffset = 1;
const ivLabelOffset = [0, sideLabelOffset, -sideLabelOffset, sideLabelOffset, -sideLabelOffset, speedLabelOffset]; 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 ivChartStatIndexes = [0, 1, 2, 5, 4, 3]; // swap special attack and speed
const defaultIvChartData = new Array(12).fill(null).map(() => 0); const defaultIvChartData = new Array(12).fill(null).map(() => 0);
export class StatsContainer extends Phaser.GameObjects.Container { export class StatsContainer extends Phaser.GameObjects.Container {
@ -29,7 +32,6 @@ export class StatsContainer extends Phaser.GameObjects.Container {
setup() { setup() {
this.setName("stats"); 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 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); const ivChartBg = this.scene.add.polygon(48, 44, ivChartBgData, 0xd8e0f0, 0.625);
ivChartBg.setOrigin(0, 0); ivChartBg.setOrigin(0, 0);
@ -55,12 +57,19 @@ export class StatsContainer extends Phaser.GameObjects.Container {
this.ivStatValueTexts = []; this.ivStatValueTexts = [];
for (const s of PERMANENT_STATS) { 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); 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.ivStatValueTexts[s].setOrigin(0.5);
this.add(statLabel); this.add(statLabel);
this.add(this.ivStatValueTexts[s]); this.add(this.ivStatValueTexts[s]);
} }

View File

@ -214,7 +214,7 @@ export default class SummaryUiHandler extends UiHandler {
this.statusContainer.add(statusLabel); 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.status.setOrigin(0.5, 0);
this.statusContainer.add(this.status); 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"}`, { 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? 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? 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 }) natureFragment: i18next.t(`pokemonSummary:natureFragment.${rawNature}`, { nature: nature })
}); });

View File

@ -1,4 +1,5 @@
import { MoneyFormat } from "#enums/money-format"; import { MoneyFormat } from "#enums/money-format";
import { Moves } from "#enums/moves";
import i18next from "i18next"; import i18next from "i18next";
export const MissingTextureKey = "__MISSING"; export const MissingTextureKey = "__MISSING";
@ -628,3 +629,12 @@ export function getLocalizedSpriteKey(baseKey: string) {
export function isBetween(num: number, min: number, max: number): boolean { export function isBetween(num: number, min: number, max: number): boolean {
return num >= min && num <= max; 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 ({ return ({
...defaultConfig, ...defaultConfig,
base: '',
esbuild: { esbuild: {
pure: mode === 'production' ? ['console.log'] : [], pure: mode === 'production' ? ['console.log'] : [],
keepNames: true, keepNames: true,