diff --git a/.env b/.env
index 7baf65d6511f..6ac42ba97b46 100644
--- a/.env
+++ b/.env
@@ -1,4 +1,3 @@
-VITE_TITLE=PokéRogue
VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=http://localhost:8001
\ No newline at end of file
diff --git a/.env.beta b/.env.beta
index 181abb016827..8d1e93b32772 100644
--- a/.env.beta
+++ b/.env.beta
@@ -1,4 +1,3 @@
-VITE_TITLE=PokéRogue Beta
VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0
-VITE_SERVER_URL=https://api.beta.pokerogue.net
+VITE_SERVER_URL=https://api.beta.pokerogue.net
\ No newline at end of file
diff --git a/.env.development b/.env.development
index a9b53e2bfb15..e9180f0875d0 100644
--- a/.env.development
+++ b/.env.development
@@ -1,4 +1,3 @@
-VITE_TITLE=PokéRogue Dev
VITE_BYPASS_LOGIN=1
VITE_BYPASS_TUTORIAL=0
-VITE_SERVER_URL=http://localhost:8001
+VITE_SERVER_URL=http://localhost:8001
\ No newline at end of file
diff --git a/.env.production b/.env.production
index a3d9d686e1ed..74818d41a12a 100644
--- a/.env.production
+++ b/.env.production
@@ -1,4 +1,3 @@
-VITE_TITLE=PokéRogue
VITE_BYPASS_LOGIN=0
VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=https://api.pokerogue.net
\ No newline at end of file
diff --git a/.github/workflows/deploy-beta.yml b/.github/workflows/deploy-beta.yml
index d55a34b95f1b..d954d9bb8657 100644
--- a/.github/workflows/deploy-beta.yml
+++ b/.github/workflows/deploy-beta.yml
@@ -20,7 +20,7 @@ jobs:
env:
NODE_ENV: production
- name: Set up SSH
- if: github.event_name == 'push' && (github.ref_name == github.event.repository.default_branch || github.ref_name == 'beta')
+ if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
run: |
mkdir ~/.ssh
echo "${{ secrets.BETA_SSH_PUBLIC_KEY }}" > ~/.ssh/id_ed25519.pub
@@ -28,6 +28,6 @@ jobs:
chmod 600 ~/.ssh/*
ssh-keyscan -H ${{ secrets.BETA_SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy build on server
- if: github.event_name == 'push' && (github.ref_name == github.event.repository.default_branch || github.ref_name == 'beta')
+ if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
run: |
rsync --del --no-times --checksum -vrm dist/* ${{ secrets.BETA_SSH_USER }}@${{ secrets.BETA_SSH_HOST }}:${{ secrets.BETA_DESTINATION_DIR }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c22d0b2ce4c1..0ae49fe9e1c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,5 +39,4 @@ coverage
# Local Documentation
/typedoc
-/dependency-graph.svg
-/.vs
+/dependency-graph.svg
\ No newline at end of file
diff --git a/MEs-Roadmap-Documentation.md b/MEs-Roadmap-Documentation.md
deleted file mode 100644
index 7e5aa1b069ec..000000000000
--- a/MEs-Roadmap-Documentation.md
+++ /dev/null
@@ -1,198 +0,0 @@
-# 📝 Most immediate things to-do list
-
-- ### High priority
- - 🐛 Intimidate and other ETB abilities proc twice at the start of wild MEs (fight or flight, dark deal)
- - ⚙️ Add a tag system so MEs don't show where they shouldn't and bricking Challenge runs:
- - noChallenge (cant be spawned in challenge runs)
- - allChallenge (can spawn in all challenge modes)
- - (typespecific)Challenge:
- - Example: fireOnly (can only spawn in fire related challenges)
-
-- ### Medium priority
-
-- ### Low priority
- - 🐛 Mysterious Challengers can spawn two trainers (or three) of the same type [Dev comment: not a bug]
- - 🐛 Fight or Flight intro visuals may show different gender from the actual spawned pokemon
-
-# 📝 Things to be done before Mystery Encounters ("MEs/Events") MVP is finished:
- All the things on this list should be done before an MVP (Minimum Viable Product) can be playtested.
-
-- ## Bugless implementation of the MVP MEs
- - Establish placeholder waves for MEs to happen ✔️
- - ⚪ Bug-free implementation of Common ME 1 ('Mysterious Chest')✔️
- - ⚪ Bug-free implementation of Common ME 2 ('Fight or Flight')✔️
- - 🔵 Bug-free implementation of Rare ME 1 ('Mysterious Challenger')✔️
- - 🔵 Bug-free implementation of Rare ME 2 ('Sleeping Snorlax') 🛠️
- - 🟣 Bug-free implementation of Epic ME 1 ('Training Session') 🛠️
- - 🟡 Bug-free implementation of Legendary ME 1 ('Dark Deal') ✔️
-
-- ## First round of playtesting (Alpha)
- - First round of feedback on bugs for more slippery bugs 🛠️
- - First round of balance feedback on odds and power-level 🛠️
- - Tweak difficulty/rewards balance in MEs 🛠️
-
- ## Translation of MEs after playtest/balance
- - First round of translators feedback to avoid potential issues 🛠️
- - EN localisation 🛠️
- - ES localisation 🛠️
-
-# 📝 Things to be done before Mystery Encounters ("MEs/Events") goes __live__:
- All the things on this list should be done before the merge to main.
-
-- ## Bugless implementation of the MVP MEs
- - Bugless implementation of about 55-60 MEs
- - 20 non-biome-dependant:
- - ⚪ 9 Common Events
- - 🔵 5 Rare Events
- - 🟣 4 Epic Events
- - 🟡 2 Legendary Events
- - 35-40 biome-dependant Events, at least one for each biome
-
-- ## Second round of playtesting (Beta)
- - Second round of feedback for bugs ❌
- - Second round of balance feedback ❌
- - Final decisions on balance, powerlevel, odds and design choices before live feedback ❌
-
- ## Translation of MEs after playtest/balance
- - de localisation 🛠️
- - en localisation 🛠️
- - es-ES localisation 🛠️
- - es-MX localisation 🛠️
- - fr localisation 🛠️
- - it localisation 🛠️
- - ko localisation 🛠️
- - pt-BR localisation 🛠️
- - zh-CN localisation 🛠️
- - zh-TW localisation 🛠️
-
-
-# 🧬 Deep dive into Events and what has been done so far
-
-Events (referred to as 'Mysterious Encounters, MEs' in the code) aim to be an addition to PokeRogue that will fundamentally shift the way PokéRogue feels. It looks to improve the bet of the game into the RogueLike genre without touching the core gameplay loop of Pokémon battles/collection that we know and love already in this game. Below there are some specifications that clarify what's being worked on for ease of access for the devs, balance team, artists and others who may be interested. Beware of spoilers!
-
-## An Event __**always has**__:
- ### #️⃣ A wave index where they're happening -- each ME takes up a whole wave (means you miss a combat!).
-
- ### 💬 Dialogue:
- - Dialogue/Message content populated in relevant locales files (namely locales/mystery-encounter.ts)
- - An associated EncounterTypeDialogue object populated in allMysteryEncounterDialogue (see data/mystery-ecounter-dialogue.ts)
- - This will require certain content, such as encounter description window text and option button labels, while some other fields will be optional
- - Key content to be aware of when writing encounter dialogue:
- - Intro dialogue or messages (shown before anything appears on screen)
- - A title (shown in description box)
- - A description (shown in description box)
- - A prompt/query to the player, to choose the options (shown in description box)
- - An option panel at the bottom, taking the space of what usually is the game dialogs + controls
- - Containing at least two options, and up to four.
- - ❗❗ To view what dialogue content is __**mandatory**__ for encounters, check the schema in data/mystery-ecounter-dialogue.ts
-
- ### 🕺 Intro Visuals:
- - One or multiple sprites may be used. They will slide onto the field when the encounter starts
- - 📚 This could be anything from a group of trainers, to a Pokemon, to a static sprite of an inanimate object
- - ❗❗ To populate an encounter with intro visuals, see "Encounter Class Extending MysteryEncounterWrapper" section
- - 📚 Technically, the encounter will still work if Intro Visuals are not provided, but your encounter will look very strange when an empty field slides onto the screen
-
- ### 📋 Encounter Class Implementing MysteryEncounterWrapper
- - ❗❗ All encounters should have their own class files organized in the src/data/mystery-encounters folder
- - ❗❗ Encounter classes can be named anything, but **must implement MysteryEncounterWrapper**
- - Refer to existing MEs for examples
- - ❗❗ As part of MysteryEncounterWrapper, they should implement their own get() function
- - 📚 The get() function should return an object that is some concrete extension of class MysteryEncounter
- - Example: can return a new OptionSelectMysteryEncounter()
- - ❗❗ **This MysteryEncounter type class will be where all encounter functional/business logic will reside**
- - 📚 That includes things like, what intro visuals to display, what each option does (is it a battle, getting items, skipping the encounter, etc.)
- - 📚 It will also serve as the way to pull data from the encounter class when starting the game
- - ❗❗ A new instance of this encounter class should be added to the initMysteryEncounters() function inside data/mystery-encounter.ts
-
- ### 🌟 **Rarity** tier of the ME, common by default.
- - ⚪ Common pool
- - 🔵 Rare pool
- - 🟣 Epic pool
- - 🟡 Legendary pool
-
- ### **Optional Requirements** for Mystery Encounters.
- - 🛠️ They give granular control over whether encounters will spawn in certain situations
- - Requirements might include:
- - Being within a wave range
- - Being a range of wave X-Y
- - Having X amount of $$$
- - Having X-Y party members (similar to catching logic?) ✔️/❌ (PARTIALLY COMPLETE)
-
- ### **MysteryEncounterOptions**
- When selected, execute the custom logic passed in the **onSelect** function. Some **MysteryEncounterOptions** could be as simple as giving the player a pokéball, and others could be a few functions chained together, like "fight a battle, and get an item if you win"
-
- ### **Functions/ Helper functions** defined in __/utils/mystery-encounter-utils.ts__ for ME to happen, if applicable. They can be:
- - Giving the player X item ✔️
- - Giving the player X item from a certain tier ✔️
- - Letting the player choose from items ✔️
- - Letting the player choose from X items from a certain tier ✔️
- - Start a combat encounter with a trainer ✔️
- - Start a combat encounter with a wild pokémon (from biome) ✔️
- - Start a combat encounter with a boss wild pokémon ✔️
- - XP to the whole party ✔️
- - Remove a PKMN from the player's party ✔️
- - Steal from player ❌
-
-# 📝 Known bugs (squash 'em all!):
- - ## 🔴 __**Really bad ones**__
- - 🐛 Picking up certain items in Fight or Flight is still broken. Workaround is leave encounter.
- - 🐛 Modifiers that are applied to pokemon get skipped in Fight or Flight.
-
- - ## 🟡 __**Bad ones under certain circumstances**__
- - 🐛 Needs further replication : At wave 51, wild PKMN encounter caused a freezed after pressing "ESC" key upon being asked to switch PKMNs
- - 🐛 Wave seed generates different encounter data if you roll to a new wave, see the spawned stuff, and refresh the app
- - 🐛 Type-buffing items (like Silk Scarf) get swapped around when offered as a reward in Fight or Flight
-
- - ## 🟢 __**Non-game breaking**__
- - Both of these bugs seem to have in common that they don't "forget" their last passed string:
- - 🐛 Scientist will remember the first PKMN it "did the thing on" and never ever forget it, even in future runs. Only affects dialogue.
- - 🐛 Tooltip bug in Events. When showing the tooltip of the 2nd or later Event you've found, the tooltip for the first option will match whatever option you selected in the previous Event. This wrong tooltip gets overriden once you move the cursor.
-
-# 🗿 Other cool things/functionalities that won't make it in the MVP but are planned to accomodate future MEs:
-
-### QoL improvements
-- Dialogue references to __**good**__ outcomes will be colored 🟢, __**bad**__ ones in 🔴 and __**ambiguous**__ or __**mixed**__, in 🟡
- - Helps with quick glances when 5x speed
-
-#### More requirements (with helper functions)
-- Having X item
-- Having Y amount of X item
-- Being in a specific Biome
-- A Pokémon X in player's party can learn Y move
-- A Pokémon X in player's party knows Y move
-- A Pokémon X in player's party has Y ability
-- A Pokémon X in player's party belongs to a pre-defined pool (ie. "Ultrabeasts")
-
-#### More outcomes (with helper functions)
-- Status one or many Pokémon if your party -- if they can be statused
-- Damage one or many Pokémon in your party
-- Set a hazard (ally or foe side)
-- Set a weather
-- Give the player a Pokémon from a pool (useful for reg. professors/traders)
-- XP to a Pokémon (similar to rare candy?)
-- Add logic for choosing a Pokémon from party for some effect (trades, sacrifices, etc)
-- Add logic for awarding exp to the party (outside of a normal combat)
-- Encounter/pull a PKMN from a pre-defined pool (ie. "Ultrabeasts")
-
-
-# Log Documentation
-
-## 12th-13th June
-- The 🐛 "Opening the chest simply moves you to a wild battle against nothingness, which you can escape after you get bored of it." is fixed.
-- The 🐛 "PKMN Sprites and their HP/lvl bar doesn't get properly recalled when finding an ME or when meeting Rival." is fixed.
-- The 🐛 "Weaker trainers from Mysterious Challenger crashes the game when the reward screen should come out" is fixed.
-- The 🐛 "If a ME spawns on the first floor of a new biome (NewBiomeEncounterPhase), intro visuals do not spawn properly" is fixed.
-- The 🐛 "Any ME that procs at wave (?)(?)(1) has its sprite removed. Only the sprite is affected." is fixed.
-- The 🐛 "Picking a double battle trainer (ie Twins) as your challenge results in a game over, including loss of save." should be fixed.
-- Allowed catch in "Fight or Flight" -- it was counterintuitive to not allow it as it __is__ a wild PKMN fight.
-- More minor 🐛 squashed.
-- Pushed Dark Deal ME to a higher wave requirement (+30) as it seems to be functioning (mostly) bugless.
-
-## 27-29th June
-- The 🐛 "Picking up certain items in Fight or Flight works poorly" has been squashed.
-- The 🐛 "Modifiers that are applied to pokemon get skipped in Fight or Flight" has been squashed.
-- ⚙️ Added "Omniboost" functionality (Fight or Flight ME)
-- The 🐛 "Wave seed generates different encounter data if you roll to a new wave, see the spawned stuff, and refresh the app" has been squashed.
-- The 🐛 "Type-buffing items (like Silk Scarf) get swapped around when offered as a reward in Fight or Flight" has been squashed.
-- ⚖️ Adjusted Dark Deal odds to show 6-7 cost PKMNs at a much higher rate (70%) than 8-cost (20%) or 9-cost (10%), to avoid box legendaries being overly present.
-- The 🐛 about "Tooltips being remembered from the previous ME choice until you hovered a different option" is squashed.
diff --git a/index.html b/index.html
index 8d078d3603b5..3722bdd34224 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
- %VITE_TITLE%
+ PokéRogue
diff --git a/public/images/items.json b/public/images/items.json
index 5642eecded28..33dcf8f5e9ad 100644
--- a/public/images/items.json
+++ b/public/images/items.json
@@ -4,8 +4,8 @@
"image": "items.png",
"format": "RGBA8888",
"size": {
- "w": 416,
- "h": 416
+ "w": 415,
+ "h": 415
},
"scale": 1,
"frames": [
@@ -744,6 +744,27 @@
"h": 24
}
},
+ {
+ "filename": "relic_gold",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 9,
+ "y": 11,
+ "w": 15,
+ "h": 11
+ },
+ "frame": {
+ "x": 0,
+ "y": 404,
+ "w": 15,
+ "h": 11
+ }
+ },
{
"filename": "calcium",
"rotated": false,
@@ -1144,7 +1165,7 @@
}
},
{
- "filename": "mind_plate",
+ "filename": "clefairy_doll",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1153,15 +1174,15 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 4,
+ "y": 5,
"w": 24,
- "h": 24
+ "h": 23
},
"frame": {
"x": 24,
"y": 392,
"w": 24,
- "h": 24
+ "h": 23
}
},
{
@@ -1228,7 +1249,7 @@
}
},
{
- "filename": "muscle_band",
+ "filename": "mind_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1249,7 +1270,7 @@
}
},
{
- "filename": "pixie_plate",
+ "filename": "muscle_band",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1270,7 +1291,7 @@
}
},
{
- "filename": "salac_berry",
+ "filename": "pixie_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1291,7 +1312,7 @@
}
},
{
- "filename": "scanner",
+ "filename": "salac_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1312,7 +1333,7 @@
}
},
{
- "filename": "silk_scarf",
+ "filename": "scanner",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1333,7 +1354,7 @@
}
},
{
- "filename": "sky_plate",
+ "filename": "coin_case",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1342,15 +1363,15 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 4,
+ "y": 5,
"w": 24,
- "h": 24
+ "h": 23
},
"frame": {
"x": 48,
"y": 392,
"w": 24,
- "h": 24
+ "h": 23
}
},
{
@@ -1396,7 +1417,7 @@
}
},
{
- "filename": "splash_plate",
+ "filename": "silk_scarf",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1417,7 +1438,7 @@
}
},
{
- "filename": "spooky_plate",
+ "filename": "sky_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1438,7 +1459,7 @@
}
},
{
- "filename": "stone_plate",
+ "filename": "splash_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1459,7 +1480,7 @@
}
},
{
- "filename": "sun_stone",
+ "filename": "spooky_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1480,7 +1501,7 @@
}
},
{
- "filename": "toxic_plate",
+ "filename": "stone_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1501,7 +1522,7 @@
}
},
{
- "filename": "zap_plate",
+ "filename": "sun_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1543,7 +1564,7 @@
}
},
{
- "filename": "clefairy_doll",
+ "filename": "toxic_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1552,19 +1573,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 5,
+ "y": 4,
"w": 24,
- "h": 23
+ "h": 24
},
"frame": {
"x": 339,
"y": 20,
"w": 24,
- "h": 23
+ "h": 24
}
},
{
- "filename": "coin_case",
+ "filename": "zap_plate",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1573,19 +1594,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 5,
+ "y": 4,
"w": 24,
- "h": 23
+ "h": 24
},
"frame": {
"x": 363,
"y": 20,
"w": 24,
- "h": 23
+ "h": 24
}
},
{
- "filename": "berry_pouch",
+ "filename": "max_revive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1593,16 +1614,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 5,
- "w": 23,
- "h": 23
+ "x": 5,
+ "y": 4,
+ "w": 22,
+ "h": 24
},
"frame": {
"x": 387,
"y": 20,
- "w": 23,
- "h": 23
+ "w": 22,
+ "h": 24
}
},
{
@@ -1753,7 +1774,7 @@
}
},
{
- "filename": "black_belt",
+ "filename": "berry_pouch",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1761,15 +1782,15 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 4,
- "w": 22,
+ "x": 4,
+ "y": 5,
+ "w": 23,
"h": 23
},
"frame": {
"x": 327,
"y": 45,
- "w": 22,
+ "w": 23,
"h": 23
}
},
@@ -1788,8 +1809,8 @@
"h": 24
},
"frame": {
- "x": 349,
- "y": 43,
+ "x": 350,
+ "y": 44,
"w": 23,
"h": 24
}
@@ -1809,14 +1830,14 @@
"h": 23
},
"frame": {
- "x": 372,
- "y": 43,
+ "x": 373,
+ "y": 44,
"w": 24,
"h": 23
}
},
{
- "filename": "red_orb",
+ "filename": "max_ether",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1824,15 +1845,15 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 7,
"y": 4,
- "w": 20,
+ "w": 18,
"h": 24
},
"frame": {
- "x": 396,
- "y": 43,
- "w": 20,
+ "x": 397,
+ "y": 44,
+ "w": 18,
"h": 24
}
},
@@ -1851,35 +1872,14 @@
"h": 18
},
"frame": {
- "x": 372,
- "y": 66,
+ "x": 373,
+ "y": 67,
"w": 24,
"h": 18
}
},
{
- "filename": "mystic_water",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 6,
- "y": 5,
- "w": 20,
- "h": 23
- },
- "frame": {
- "x": 396,
- "y": 67,
- "w": 20,
- "h": 23
- }
- },
- {
- "filename": "amulet_coin",
+ "filename": "max_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -1887,16 +1887,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 5,
- "w": 23,
- "h": 21
+ "x": 7,
+ "y": 4,
+ "w": 18,
+ "h": 24
},
"frame": {
- "x": 349,
- "y": 67,
- "w": 23,
- "h": 21
+ "x": 397,
+ "y": 68,
+ "w": 18,
+ "h": 24
}
},
{
@@ -1914,54 +1914,12 @@
"h": 18
},
"frame": {
- "x": 372,
- "y": 84,
+ "x": 67,
+ "y": 50,
"w": 24,
"h": 18
}
},
- {
- "filename": "hard_meteorite",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 7,
- "y": 5,
- "w": 20,
- "h": 22
- },
- "frame": {
- "x": 396,
- "y": 90,
- "w": 20,
- "h": 22
- }
- },
- {
- "filename": "relic_gold",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 9,
- "y": 11,
- "w": 15,
- "h": 11
- },
- "frame": {
- "x": 0,
- "y": 404,
- "w": 15,
- "h": 11
- }
- },
{
"filename": "icy_reins_of_unity",
"rotated": false,
@@ -1976,27 +1934,6 @@
"w": 24,
"h": 20
},
- "frame": {
- "x": 67,
- "y": 50,
- "w": 24,
- "h": 20
- }
- },
- {
- "filename": "metal_powder",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 4,
- "y": 6,
- "w": 24,
- "h": 20
- },
"frame": {
"x": 91,
"y": 50,
@@ -2026,7 +1963,7 @@
}
},
{
- "filename": "peat_block",
+ "filename": "metal_powder",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2035,19 +1972,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 5,
+ "y": 6,
"w": 24,
- "h": 22
+ "h": 20
},
"frame": {
"x": 136,
"y": 60,
"w": 24,
- "h": 22
+ "h": 20
}
},
{
- "filename": "quick_powder",
+ "filename": "peat_block",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2056,19 +1993,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 6,
+ "y": 5,
"w": 24,
- "h": 20
+ "h": 22
},
"frame": {
"x": 160,
"y": 67,
"w": 24,
- "h": 20
+ "h": 22
}
},
{
- "filename": "rusted_shield",
+ "filename": "dynamax_band",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2077,19 +2014,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 6,
- "w": 24,
- "h": 20
+ "y": 4,
+ "w": 23,
+ "h": 23
},
"frame": {
"x": 184,
"y": 67,
- "w": 24,
- "h": 20
+ "w": 23,
+ "h": 23
}
},
{
- "filename": "auspicious_armor",
+ "filename": "griseous_core",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2097,20 +2034,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
+ "x": 5,
"y": 5,
"w": 23,
- "h": 21
+ "h": 23
},
"frame": {
- "x": 208,
+ "x": 207,
"y": 67,
"w": 23,
- "h": 21
+ "h": 23
}
},
{
- "filename": "sacred_ash",
+ "filename": "healing_charm",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2118,20 +2055,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 7,
- "w": 24,
- "h": 20
+ "x": 5,
+ "y": 5,
+ "w": 23,
+ "h": 22
},
"frame": {
- "x": 231,
+ "x": 230,
"y": 68,
- "w": 24,
- "h": 20
+ "w": 23,
+ "h": 22
}
},
{
- "filename": "shadow_reins_of_unity",
+ "filename": "rare_candy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2140,19 +2077,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 7,
- "w": 24,
- "h": 20
+ "y": 5,
+ "w": 23,
+ "h": 23
},
"frame": {
- "x": 255,
+ "x": 253,
"y": 68,
- "w": 24,
- "h": 20
+ "w": 23,
+ "h": 23
}
},
{
- "filename": "soft_sand",
+ "filename": "rarer_candy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2161,19 +2098,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 7,
- "w": 24,
- "h": 20
+ "y": 5,
+ "w": 23,
+ "h": 23
},
"frame": {
- "x": 279,
+ "x": 276,
"y": 68,
- "w": 24,
- "h": 20
+ "w": 23,
+ "h": 23
}
},
{
- "filename": "binding_band",
+ "filename": "stick",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2181,20 +2118,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 6,
+ "x": 4,
+ "y": 5,
"w": 23,
- "h": 20
+ "h": 23
},
"frame": {
- "x": 303,
+ "x": 299,
"y": 68,
"w": 23,
- "h": 20
+ "h": 23
}
},
{
- "filename": "dynamax_band",
+ "filename": "black_belt",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2202,20 +2139,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
+ "x": 5,
"y": 4,
- "w": 23,
+ "w": 22,
"h": 23
},
"frame": {
- "x": 326,
+ "x": 322,
"y": 68,
- "w": 23,
+ "w": 22,
"h": 23
}
},
{
- "filename": "black_glasses",
+ "filename": "bug_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2223,20 +2160,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 8,
- "w": 23,
- "h": 17
+ "x": 6,
+ "y": 4,
+ "w": 22,
+ "h": 23
},
"frame": {
- "x": 349,
- "y": 88,
- "w": 23,
- "h": 17
+ "x": 344,
+ "y": 68,
+ "w": 22,
+ "h": 23
}
},
{
- "filename": "burn_drive",
+ "filename": "quick_powder",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2245,19 +2182,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 8,
- "w": 23,
- "h": 17
+ "y": 6,
+ "w": 24,
+ "h": 20
},
"frame": {
"x": 60,
- "y": 70,
- "w": 23,
- "h": 17
+ "y": 68,
+ "w": 24,
+ "h": 20
}
},
{
- "filename": "griseous_core",
+ "filename": "dark_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2265,20 +2202,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 23,
+ "x": 6,
+ "y": 4,
+ "w": 22,
"h": 23
},
"frame": {
"x": 57,
- "y": 87,
- "w": 23,
+ "y": 88,
+ "w": 22,
"h": 23
}
},
{
- "filename": "max_revive",
+ "filename": "dragon_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2286,20 +2223,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 6,
"y": 4,
"w": 22,
- "h": 24
+ "h": 23
},
"frame": {
"x": 57,
- "y": 110,
+ "y": 111,
"w": 22,
- "h": 24
+ "h": 23
}
},
{
- "filename": "bug_tera_shard",
+ "filename": "electric_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2320,7 +2257,7 @@
}
},
{
- "filename": "chill_drive",
+ "filename": "rusted_shield",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2329,19 +2266,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 8,
- "w": 23,
- "h": 17
+ "y": 6,
+ "w": 24,
+ "h": 20
},
"frame": {
- "x": 83,
+ "x": 84,
"y": 70,
- "w": 23,
- "h": 17
+ "w": 24,
+ "h": 20
}
},
{
- "filename": "rare_candy",
+ "filename": "fairy_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2349,20 +2286,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 5,
- "w": 23,
+ "x": 6,
+ "y": 4,
+ "w": 22,
"h": 23
},
"frame": {
- "x": 80,
- "y": 87,
- "w": 23,
+ "x": 79,
+ "y": 90,
+ "w": 22,
"h": 23
}
},
{
- "filename": "rarer_candy",
+ "filename": "fighting_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2370,20 +2307,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 5,
- "w": 23,
+ "x": 6,
+ "y": 4,
+ "w": 22,
"h": 23
},
"frame": {
"x": 79,
- "y": 110,
- "w": 23,
+ "y": 113,
+ "w": 22,
"h": 23
}
},
{
- "filename": "stick",
+ "filename": "amulet_coin",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2391,20 +2328,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
+ "x": 6,
"y": 5,
"w": 23,
- "h": 23
+ "h": 21
},
"frame": {
"x": 79,
- "y": 133,
+ "y": 136,
"w": 23,
- "h": 23
+ "h": 21
}
},
{
- "filename": "big_mushroom",
+ "filename": "coupon",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2412,20 +2349,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 19,
+ "x": 4,
+ "y": 7,
+ "w": 23,
"h": 19
},
"frame": {
"x": 63,
"y": 157,
- "w": 19,
+ "w": 23,
"h": 19
}
},
{
- "filename": "max_ether",
+ "filename": "fire_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2433,20 +2370,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 4,
- "w": 18,
- "h": 24
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 23
},
"frame": {
"x": 64,
"y": 176,
- "w": 18,
- "h": 24
+ "w": 22,
+ "h": 23
}
},
{
- "filename": "oval_charm",
+ "filename": "fire_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2456,18 +2393,18 @@
"spriteSourceSize": {
"x": 6,
"y": 4,
- "w": 21,
- "h": 24
+ "w": 22,
+ "h": 23
},
"frame": {
- "x": 82,
- "y": 156,
- "w": 21,
- "h": 24
+ "x": 64,
+ "y": 199,
+ "w": 22,
+ "h": 23
}
},
{
- "filename": "max_potion",
+ "filename": "flying_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2475,20 +2412,41 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
+ "x": 6,
"y": 4,
- "w": 18,
- "h": 24
+ "w": 22,
+ "h": 23
},
"frame": {
"x": 64,
- "y": 200,
- "w": 18,
+ "y": 222,
+ "w": 22,
+ "h": 23
+ }
+ },
+ {
+ "filename": "max_lure",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 8,
+ "y": 4,
+ "w": 17,
+ "h": 24
+ },
+ "frame": {
+ "x": 86,
+ "y": 157,
+ "w": 17,
"h": 24
}
},
{
- "filename": "shiny_charm",
+ "filename": "oval_charm",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2502,14 +2460,14 @@
"h": 24
},
"frame": {
- "x": 64,
- "y": 224,
+ "x": 86,
+ "y": 181,
"w": 21,
"h": 24
}
},
{
- "filename": "dark_tera_shard",
+ "filename": "shiny_charm",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2519,18 +2477,18 @@
"spriteSourceSize": {
"x": 6,
"y": 4,
- "w": 22,
- "h": 23
+ "w": 21,
+ "h": 24
},
"frame": {
- "x": 82,
- "y": 180,
- "w": 22,
- "h": 23
+ "x": 86,
+ "y": 205,
+ "w": 21,
+ "h": 24
}
},
{
- "filename": "deep_sea_tooth",
+ "filename": "auspicious_armor",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2538,20 +2496,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 6,
- "w": 22,
+ "x": 4,
+ "y": 5,
+ "w": 23,
"h": 21
},
"frame": {
- "x": 82,
- "y": 203,
- "w": 22,
+ "x": 86,
+ "y": 229,
+ "w": 23,
"h": 21
}
},
{
- "filename": "dragon_tera_shard",
+ "filename": "full_heal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2559,41 +2517,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 9,
"y": 4,
- "w": 22,
+ "w": 15,
"h": 23
},
- "frame": {
- "x": 85,
- "y": 224,
- "w": 22,
- "h": 23
- }
- },
- {
- "filename": "max_lure",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 8,
- "y": 4,
- "w": 17,
- "h": 24
- },
"frame": {
"x": 71,
- "y": 248,
- "w": 17,
- "h": 24
+ "y": 245,
+ "w": 15,
+ "h": 23
}
},
{
- "filename": "electric_tera_shard",
+ "filename": "binding_band",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2601,20 +2538,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 5,
+ "y": 6,
+ "w": 23,
+ "h": 20
},
"frame": {
- "x": 88,
- "y": 247,
- "w": 22,
- "h": 23
+ "x": 86,
+ "y": 250,
+ "w": 23,
+ "h": 20
}
},
{
- "filename": "max_repel",
+ "filename": "sacred_ash",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2622,20 +2559,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 4,
- "w": 16,
- "h": 24
+ "x": 4,
+ "y": 7,
+ "w": 24,
+ "h": 20
},
"frame": {
- "x": 72,
- "y": 272,
- "w": 16,
- "h": 24
+ "x": 108,
+ "y": 73,
+ "w": 24,
+ "h": 20
}
},
{
- "filename": "fairy_tera_shard",
+ "filename": "focus_sash",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2643,20 +2580,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 5,
"y": 4,
"w": 22,
"h": 23
},
"frame": {
- "x": 88,
- "y": 270,
+ "x": 101,
+ "y": 93,
"w": 22,
"h": 23
}
},
{
- "filename": "pp_max",
+ "filename": "deep_sea_scale",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2664,20 +2601,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 4,
- "w": 16,
- "h": 24
+ "x": 5,
+ "y": 6,
+ "w": 22,
+ "h": 20
},
"frame": {
- "x": 72,
- "y": 296,
- "w": 16,
- "h": 24
+ "x": 101,
+ "y": 116,
+ "w": 22,
+ "h": 20
}
},
{
- "filename": "fighting_tera_shard",
+ "filename": "deep_sea_tooth",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2685,20 +2622,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
+ "x": 5,
+ "y": 6,
"w": 22,
- "h": 23
+ "h": 21
},
"frame": {
- "x": 88,
- "y": 293,
+ "x": 102,
+ "y": 136,
"w": 22,
- "h": 23
+ "h": 21
}
},
{
- "filename": "pp_up",
+ "filename": "red_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2706,41 +2643,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 4,
- "w": 16,
+ "w": 20,
"h": 24
},
"frame": {
- "x": 72,
- "y": 320,
- "w": 16,
+ "x": 103,
+ "y": 157,
+ "w": 20,
"h": 24
}
},
{
- "filename": "fire_stone",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
- "h": 23
- },
- "frame": {
- "x": 88,
- "y": 316,
- "w": 22,
- "h": 23
- }
- },
- {
- "filename": "protein",
+ "filename": "max_repel",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2754,14 +2670,14 @@
"h": 24
},
"frame": {
- "x": 72,
- "y": 344,
+ "x": 107,
+ "y": 181,
"w": 16,
"h": 24
}
},
{
- "filename": "fire_tera_shard",
+ "filename": "pp_max",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2769,20 +2685,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 4,
- "w": 22,
- "h": 23
+ "w": 16,
+ "h": 24
},
"frame": {
- "x": 88,
- "y": 339,
- "w": 22,
- "h": 23
+ "x": 107,
+ "y": 205,
+ "w": 16,
+ "h": 24
}
},
{
- "filename": "repel",
+ "filename": "pp_up",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2796,14 +2712,14 @@
"h": 24
},
"frame": {
- "x": 72,
- "y": 368,
+ "x": 109,
+ "y": 229,
"w": 16,
"h": 24
}
},
{
- "filename": "super_lure",
+ "filename": "apicot_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2811,20 +2727,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 4,
- "w": 17,
- "h": 24
+ "x": 6,
+ "y": 6,
+ "w": 19,
+ "h": 20
},
"frame": {
- "x": 72,
- "y": 392,
- "w": 17,
- "h": 24
+ "x": 109,
+ "y": 253,
+ "w": 19,
+ "h": 20
}
},
{
- "filename": "flying_tera_shard",
+ "filename": "protein",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2832,20 +2748,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 4,
- "w": 22,
- "h": 23
+ "w": 16,
+ "h": 24
},
"frame": {
- "x": 88,
- "y": 362,
- "w": 22,
- "h": 23
+ "x": 123,
+ "y": 93,
+ "w": 16,
+ "h": 24
}
},
{
- "filename": "focus_sash",
+ "filename": "lansat_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2855,18 +2771,18 @@
"spriteSourceSize": {
"x": 5,
"y": 4,
- "w": 22,
+ "w": 21,
"h": 23
},
"frame": {
- "x": 89,
- "y": 385,
- "w": 22,
+ "x": 139,
+ "y": 80,
+ "w": 21,
"h": 23
}
},
{
- "filename": "coupon",
+ "filename": "shadow_reins_of_unity",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2876,18 +2792,18 @@
"spriteSourceSize": {
"x": 4,
"y": 7,
- "w": 23,
- "h": 19
+ "w": 24,
+ "h": 20
},
"frame": {
- "x": 106,
- "y": 73,
- "w": 23,
- "h": 19
+ "x": 160,
+ "y": 89,
+ "w": 24,
+ "h": 20
}
},
{
- "filename": "golden_mystic_ticket",
+ "filename": "soft_sand",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2897,18 +2813,18 @@
"spriteSourceSize": {
"x": 4,
"y": 7,
- "w": 23,
- "h": 19
+ "w": 24,
+ "h": 20
},
"frame": {
- "x": 103,
- "y": 92,
- "w": 23,
- "h": 19
+ "x": 184,
+ "y": 90,
+ "w": 24,
+ "h": 20
}
},
{
- "filename": "ghost_tera_shard",
+ "filename": "moon_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2916,16 +2832,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 4,
+ "y": 6,
+ "w": 23,
+ "h": 21
},
"frame": {
- "x": 102,
- "y": 111,
- "w": 22,
- "h": 23
+ "x": 208,
+ "y": 90,
+ "w": 23,
+ "h": 21
}
},
{
@@ -2943,14 +2859,14 @@
"h": 22
},
"frame": {
- "x": 102,
- "y": 134,
+ "x": 231,
+ "y": 90,
"w": 22,
"h": 22
}
},
{
- "filename": "grass_tera_shard",
+ "filename": "n_lunarizer",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2958,20 +2874,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 4,
+ "y": 6,
+ "w": 23,
+ "h": 21
},
"frame": {
- "x": 103,
- "y": 156,
- "w": 22,
- "h": 23
+ "x": 253,
+ "y": 91,
+ "w": 23,
+ "h": 21
}
},
{
- "filename": "ground_tera_shard",
+ "filename": "n_solarizer",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -2979,20 +2895,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 4,
+ "y": 6,
+ "w": 23,
+ "h": 21
},
"frame": {
- "x": 104,
- "y": 179,
- "w": 22,
- "h": 23
+ "x": 276,
+ "y": 91,
+ "w": 23,
+ "h": 21
}
},
{
- "filename": "bug_memory",
+ "filename": "rusted_sword",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3000,20 +2916,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 4,
"y": 5,
- "w": 22,
+ "w": 23,
"h": 22
},
"frame": {
- "x": 104,
- "y": 202,
- "w": 22,
+ "x": 299,
+ "y": 91,
+ "w": 23,
"h": 22
}
},
{
- "filename": "ice_tera_shard",
+ "filename": "bug_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3021,20 +2937,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
+ "x": 5,
+ "y": 5,
"w": 22,
- "h": 23
+ "h": 22
},
"frame": {
- "x": 107,
- "y": 224,
+ "x": 322,
+ "y": 91,
"w": 22,
- "h": 23
+ "h": 22
}
},
{
- "filename": "lansat_berry",
+ "filename": "charcoal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3043,19 +2959,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 4,
- "w": 21,
- "h": 23
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 110,
- "y": 247,
- "w": 21,
- "h": 23
+ "x": 344,
+ "y": 91,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "leaf_stone",
+ "filename": "dusk_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3063,41 +2979,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 6,
"w": 21,
- "h": 23
+ "h": 21
},
"frame": {
- "x": 110,
- "y": 270,
+ "x": 139,
+ "y": 103,
"w": 21,
- "h": 23
- }
- },
- {
- "filename": "never_melt_ice",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
- "h": 23
- },
- "frame": {
- "x": 110,
- "y": 293,
- "w": 22,
- "h": 23
+ "h": 21
}
},
{
- "filename": "normal_tera_shard",
+ "filename": "mystery_egg",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3105,20 +3000,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 8,
+ "y": 8,
+ "w": 16,
+ "h": 18
},
"frame": {
- "x": 110,
- "y": 316,
- "w": 22,
- "h": 23
+ "x": 123,
+ "y": 117,
+ "w": 16,
+ "h": 18
}
},
{
- "filename": "petaya_berry",
+ "filename": "black_glasses",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3126,20 +3021,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
- "h": 23
+ "x": 4,
+ "y": 8,
+ "w": 23,
+ "h": 17
},
"frame": {
- "x": 110,
- "y": 339,
- "w": 22,
- "h": 23
+ "x": 160,
+ "y": 109,
+ "w": 23,
+ "h": 17
}
},
{
- "filename": "poison_tera_shard",
+ "filename": "burn_drive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3147,20 +3042,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 22,
- "h": 23
+ "x": 4,
+ "y": 8,
+ "w": 23,
+ "h": 17
},
"frame": {
- "x": 110,
- "y": 362,
- "w": 22,
- "h": 23
+ "x": 183,
+ "y": 110,
+ "w": 23,
+ "h": 17
}
},
{
- "filename": "psychic_tera_shard",
+ "filename": "ghost_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3174,14 +3069,14 @@
"h": 23
},
"frame": {
- "x": 111,
- "y": 385,
+ "x": 366,
+ "y": 85,
"w": 22,
"h": 23
}
},
{
- "filename": "douse_drive",
+ "filename": "chill_drive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3195,14 +3090,14 @@
"h": 17
},
"frame": {
- "x": 372,
- "y": 102,
+ "x": 206,
+ "y": 111,
"w": 23,
"h": 17
}
},
{
- "filename": "sharp_beak",
+ "filename": "douse_drive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3210,20 +3105,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 21,
- "h": 23
+ "x": 4,
+ "y": 8,
+ "w": 23,
+ "h": 17
},
"frame": {
- "x": 395,
+ "x": 229,
"y": 112,
- "w": 21,
- "h": 23
+ "w": 23,
+ "h": 17
}
},
{
- "filename": "healing_charm",
+ "filename": "golden_mystic_ticket",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3231,20 +3126,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 4,
+ "y": 7,
"w": 23,
- "h": 22
+ "h": 19
},
"frame": {
- "x": 129,
- "y": 82,
+ "x": 252,
+ "y": 112,
"w": 23,
- "h": 22
+ "h": 19
}
},
{
- "filename": "moon_stone",
+ "filename": "mystic_ticket",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3253,19 +3148,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 6,
+ "y": 7,
"w": 23,
- "h": 21
+ "h": 19
},
"frame": {
- "x": 152,
- "y": 87,
+ "x": 275,
+ "y": 112,
"w": 23,
- "h": 21
+ "h": 19
}
},
{
- "filename": "n_lunarizer",
+ "filename": "pair_of_tickets",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3274,19 +3169,19 @@
},
"spriteSourceSize": {
"x": 4,
- "y": 6,
+ "y": 7,
"w": 23,
- "h": 21
+ "h": 19
},
"frame": {
- "x": 175,
- "y": 87,
+ "x": 298,
+ "y": 113,
"w": 23,
- "h": 21
+ "h": 19
}
},
{
- "filename": "n_solarizer",
+ "filename": "reviver_seed",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3294,20 +3189,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 6,
+ "x": 5,
+ "y": 8,
"w": 23,
- "h": 21
+ "h": 20
},
"frame": {
- "x": 198,
- "y": 88,
+ "x": 321,
+ "y": 113,
"w": 23,
- "h": 21
+ "h": 20
}
},
{
- "filename": "rusted_sword",
+ "filename": "dark_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3315,20 +3210,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
+ "x": 5,
"y": 5,
- "w": 23,
+ "w": 22,
"h": 22
},
"frame": {
- "x": 221,
- "y": 88,
- "w": 23,
+ "x": 344,
+ "y": 113,
+ "w": 22,
"h": 22
}
},
{
- "filename": "charcoal",
+ "filename": "grass_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3336,20 +3231,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 244,
- "y": 88,
+ "x": 366,
+ "y": 108,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "dark_memory",
+ "filename": "berry_pot",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3357,20 +3252,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 7,
"y": 5,
- "w": 22,
+ "w": 18,
"h": 22
},
"frame": {
- "x": 266,
- "y": 88,
- "w": 22,
+ "x": 124,
+ "y": 135,
+ "w": 18,
"h": 22
}
},
{
- "filename": "dire_hit",
+ "filename": "ground_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3378,20 +3273,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 288,
- "y": 88,
+ "x": 123,
+ "y": 157,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "super_repel",
+ "filename": "ice_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3399,20 +3294,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 4,
- "w": 16,
- "h": 24
+ "w": 22,
+ "h": 23
},
"frame": {
- "x": 310,
- "y": 88,
- "w": 16,
- "h": 24
+ "x": 123,
+ "y": 180,
+ "w": 22,
+ "h": 23
}
},
{
- "filename": "wellspring_mask",
+ "filename": "never_melt_ice",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3420,20 +3315,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
+ "x": 5,
"y": 5,
- "w": 23,
- "h": 21
+ "w": 22,
+ "h": 23
},
"frame": {
- "x": 326,
- "y": 91,
- "w": 23,
- "h": 21
+ "x": 123,
+ "y": 203,
+ "w": 22,
+ "h": 23
}
},
{
- "filename": "mystic_ticket",
+ "filename": "leaf_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3441,20 +3336,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 7,
- "w": 23,
- "h": 19
+ "x": 5,
+ "y": 5,
+ "w": 21,
+ "h": 23
},
"frame": {
- "x": 349,
- "y": 105,
- "w": 23,
- "h": 19
+ "x": 125,
+ "y": 226,
+ "w": 21,
+ "h": 23
}
},
{
- "filename": "pair_of_tickets",
+ "filename": "mystic_water",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3462,20 +3357,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 7,
- "w": 23,
- "h": 19
+ "x": 6,
+ "y": 5,
+ "w": 20,
+ "h": 23
},
"frame": {
- "x": 372,
- "y": 119,
- "w": 23,
- "h": 19
+ "x": 128,
+ "y": 249,
+ "w": 20,
+ "h": 23
}
},
{
- "filename": "whipped_dream",
+ "filename": "normal_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3483,20 +3378,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 6,
"y": 4,
- "w": 21,
+ "w": 22,
"h": 23
},
"frame": {
- "x": 395,
- "y": 135,
- "w": 21,
+ "x": 388,
+ "y": 92,
+ "w": 22,
"h": 23
}
},
{
- "filename": "relic_crown",
+ "filename": "blunder_policy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3504,20 +3399,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 4,
- "y": 7,
- "w": 23,
- "h": 18
+ "x": 5,
+ "y": 6,
+ "w": 22,
+ "h": 19
},
"frame": {
- "x": 126,
- "y": 104,
- "w": 23,
- "h": 18
+ "x": 388,
+ "y": 115,
+ "w": 22,
+ "h": 19
}
},
{
- "filename": "reaper_cloth",
+ "filename": "sachet",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3525,20 +3420,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
+ "x": 6,
+ "y": 4,
+ "w": 18,
"h": 23
},
"frame": {
- "x": 124,
- "y": 122,
- "w": 22,
+ "x": 142,
+ "y": 124,
+ "w": 18,
"h": 23
}
},
{
- "filename": "reviver_seed",
+ "filename": "wellspring_mask",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3546,16 +3441,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 8,
+ "x": 4,
+ "y": 5,
"w": 23,
- "h": 20
+ "h": 21
},
"frame": {
- "x": 149,
- "y": 108,
+ "x": 160,
+ "y": 126,
"w": 23,
- "h": 20
+ "h": 21
}
},
{
@@ -3573,14 +3468,14 @@
"h": 20
},
"frame": {
- "x": 172,
- "y": 108,
+ "x": 183,
+ "y": 127,
"w": 23,
"h": 20
}
},
{
- "filename": "blunder_policy",
+ "filename": "relic_crown",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3588,16 +3483,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 6,
- "w": 22,
- "h": 19
+ "x": 4,
+ "y": 7,
+ "w": 23,
+ "h": 18
},
"frame": {
- "x": 195,
- "y": 109,
- "w": 22,
- "h": 19
+ "x": 206,
+ "y": 128,
+ "w": 23,
+ "h": 18
}
},
{
@@ -3615,8 +3510,8 @@
"h": 17
},
"frame": {
- "x": 146,
- "y": 128,
+ "x": 229,
+ "y": 129,
"w": 23,
"h": 17
}
@@ -3636,14 +3531,56 @@
"h": 17
},
"frame": {
- "x": 169,
- "y": 128,
+ "x": 252,
+ "y": 131,
"w": 23,
"h": 17
}
},
{
- "filename": "deep_sea_scale",
+ "filename": "dire_hit",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 22
+ },
+ "frame": {
+ "x": 275,
+ "y": 131,
+ "w": 22,
+ "h": 22
+ }
+ },
+ {
+ "filename": "dna_splicers",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 22
+ },
+ "frame": {
+ "x": 297,
+ "y": 132,
+ "w": 22,
+ "h": 22
+ }
+ },
+ {
+ "filename": "dragon_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3652,19 +3589,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
+ "y": 5,
"w": 22,
- "h": 20
+ "h": 22
},
"frame": {
- "x": 192,
- "y": 128,
+ "x": 319,
+ "y": 133,
"w": 22,
- "h": 20
+ "h": 22
}
},
{
- "filename": "dna_splicers",
+ "filename": "electirizer",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3678,14 +3615,14 @@
"h": 22
},
"frame": {
- "x": 217,
- "y": 110,
+ "x": 341,
+ "y": 135,
"w": 22,
"h": 22
}
},
{
- "filename": "dragon_memory",
+ "filename": "petaya_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3696,17 +3633,17 @@
"x": 5,
"y": 5,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 239,
- "y": 110,
+ "x": 145,
+ "y": 147,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "electirizer",
+ "filename": "poison_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3714,20 +3651,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 261,
- "y": 110,
+ "x": 167,
+ "y": 147,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "electric_memory",
+ "filename": "psychic_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3735,20 +3672,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 283,
- "y": 110,
+ "x": 145,
+ "y": 170,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "enigma_berry",
+ "filename": "reaper_cloth",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3759,17 +3696,17 @@
"x": 5,
"y": 5,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 305,
- "y": 112,
+ "x": 145,
+ "y": 193,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "fairy_memory",
+ "filename": "rock_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3777,20 +3714,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 327,
- "y": 112,
+ "x": 167,
+ "y": 170,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "dubious_disc",
+ "filename": "steel_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3798,20 +3735,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 7,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 19
+ "h": 23
},
"frame": {
- "x": 214,
- "y": 132,
+ "x": 167,
+ "y": 193,
"w": 22,
- "h": 19
+ "h": 23
}
},
{
- "filename": "fairy_feather",
+ "filename": "super_lure",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3819,20 +3756,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 7,
- "w": 22,
- "h": 20
+ "x": 8,
+ "y": 4,
+ "w": 17,
+ "h": 24
},
"frame": {
- "x": 236,
- "y": 132,
- "w": 22,
- "h": 20
+ "x": 189,
+ "y": 147,
+ "w": 17,
+ "h": 24
}
},
{
- "filename": "fighting_memory",
+ "filename": "stellar_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3840,20 +3777,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 258,
- "y": 132,
+ "x": 206,
+ "y": 146,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "fire_memory",
+ "filename": "water_tera_shard",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3861,20 +3798,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
+ "x": 6,
+ "y": 4,
"w": 22,
- "h": 22
+ "h": 23
},
"frame": {
- "x": 280,
- "y": 132,
+ "x": 228,
+ "y": 146,
"w": 22,
- "h": 22
+ "h": 23
}
},
{
- "filename": "flying_memory",
+ "filename": "electric_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3888,14 +3825,14 @@
"h": 22
},
"frame": {
- "x": 302,
- "y": 134,
+ "x": 250,
+ "y": 148,
"w": 22,
"h": 22
}
},
{
- "filename": "ganlon_berry",
+ "filename": "hyper_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3903,20 +3840,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 8,
"y": 5,
- "w": 22,
- "h": 22
+ "w": 17,
+ "h": 23
},
"frame": {
- "x": 324,
- "y": 134,
- "w": 22,
- "h": 22
+ "x": 189,
+ "y": 171,
+ "w": 17,
+ "h": 23
}
},
{
- "filename": "rock_tera_shard",
+ "filename": "wide_lens",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3924,20 +3861,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 5,
"y": 4,
"w": 22,
"h": 23
},
"frame": {
- "x": 125,
- "y": 145,
+ "x": 206,
+ "y": 169,
"w": 22,
"h": 23
}
},
{
- "filename": "steel_tera_shard",
+ "filename": "enigma_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3945,20 +3882,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
+ "x": 5,
+ "y": 5,
"w": 22,
- "h": 23
+ "h": 22
},
"frame": {
- "x": 147,
- "y": 145,
+ "x": 228,
+ "y": 169,
"w": 22,
- "h": 23
+ "h": 22
}
},
{
- "filename": "stellar_tera_shard",
+ "filename": "fairy_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3966,20 +3903,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
+ "x": 5,
+ "y": 5,
"w": 22,
- "h": 23
+ "h": 22
},
"frame": {
- "x": 169,
- "y": 145,
+ "x": 250,
+ "y": 170,
"w": 22,
- "h": 23
+ "h": 22
}
},
{
- "filename": "ghost_memory",
+ "filename": "fighting_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -3993,14 +3930,14 @@
"h": 22
},
"frame": {
- "x": 191,
- "y": 148,
+ "x": 272,
+ "y": 153,
"w": 22,
"h": 22
}
},
{
- "filename": "grass_memory",
+ "filename": "fire_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4014,14 +3951,14 @@
"h": 22
},
"frame": {
- "x": 213,
- "y": 151,
+ "x": 294,
+ "y": 154,
"w": 22,
"h": 22
}
},
{
- "filename": "ground_memory",
+ "filename": "dubious_disc",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4030,19 +3967,40 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 7,
"w": 22,
- "h": 22
+ "h": 19
},
"frame": {
- "x": 235,
- "y": 152,
+ "x": 272,
+ "y": 175,
"w": 22,
- "h": 22
+ "h": 19
}
},
{
- "filename": "guard_spec",
+ "filename": "fairy_feather",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 7,
+ "w": 22,
+ "h": 20
+ },
+ "frame": {
+ "x": 294,
+ "y": 176,
+ "w": 22,
+ "h": 20
+ }
+ },
+ {
+ "filename": "flying_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4056,14 +4014,14 @@
"h": 22
},
"frame": {
- "x": 257,
- "y": 154,
+ "x": 316,
+ "y": 155,
"w": 22,
"h": 22
}
},
{
- "filename": "ice_memory",
+ "filename": "ganlon_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4077,14 +4035,14 @@
"h": 22
},
"frame": {
- "x": 279,
- "y": 154,
+ "x": 316,
+ "y": 177,
"w": 22,
"h": 22
}
},
{
- "filename": "ice_stone",
+ "filename": "ghost_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4098,14 +4056,14 @@
"h": 22
},
"frame": {
- "x": 301,
- "y": 156,
+ "x": 338,
+ "y": 157,
"w": 22,
"h": 22
}
},
{
- "filename": "magmarizer",
+ "filename": "grass_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4119,14 +4077,14 @@
"h": 22
},
"frame": {
- "x": 323,
- "y": 156,
+ "x": 338,
+ "y": 179,
"w": 22,
"h": 22
}
},
{
- "filename": "water_tera_shard",
+ "filename": "ground_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4134,20 +4092,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
+ "x": 5,
+ "y": 5,
"w": 22,
- "h": 23
+ "h": 22
},
"frame": {
- "x": 126,
- "y": 168,
+ "x": 189,
+ "y": 194,
"w": 22,
- "h": 23
+ "h": 22
}
},
{
- "filename": "wide_lens",
+ "filename": "potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4155,20 +4113,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 4,
- "w": 22,
+ "x": 8,
+ "y": 5,
+ "w": 17,
"h": 23
},
"frame": {
- "x": 148,
- "y": 168,
- "w": 22,
+ "x": 211,
+ "y": 192,
+ "w": 17,
"h": 23
}
},
{
- "filename": "dusk_stone",
+ "filename": "guard_spec",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4176,20 +4134,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 21,
- "h": 21
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 170,
- "y": 168,
- "w": 21,
- "h": 21
+ "x": 228,
+ "y": 191,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "liechi_berry",
+ "filename": "ice_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4198,19 +4156,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
+ "y": 5,
"w": 22,
- "h": 21
+ "h": 22
},
"frame": {
- "x": 191,
- "y": 170,
+ "x": 250,
+ "y": 192,
"w": 22,
- "h": 21
+ "h": 22
}
},
{
- "filename": "mini_black_hole",
+ "filename": "ice_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4224,14 +4182,14 @@
"h": 22
},
"frame": {
- "x": 126,
- "y": 191,
+ "x": 272,
+ "y": 194,
"w": 22,
"h": 22
}
},
{
- "filename": "poison_memory",
+ "filename": "liechi_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4240,19 +4198,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 6,
"w": 22,
- "h": 22
+ "h": 21
},
"frame": {
- "x": 148,
- "y": 191,
+ "x": 294,
+ "y": 196,
"w": 22,
- "h": 22
+ "h": 21
}
},
{
- "filename": "poison_barb",
+ "filename": "magmarizer",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4261,15 +4219,15 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
- "w": 21,
- "h": 21
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 170,
- "y": 189,
- "w": 21,
- "h": 21
+ "x": 316,
+ "y": 199,
+ "w": 22,
+ "h": 22
}
},
{
@@ -4287,14 +4245,14 @@
"h": 20
},
"frame": {
- "x": 213,
- "y": 173,
+ "x": 338,
+ "y": 201,
"w": 22,
"h": 20
}
},
{
- "filename": "protector",
+ "filename": "mini_black_hole",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4308,14 +4266,14 @@
"h": 22
},
"frame": {
- "x": 235,
- "y": 174,
+ "x": 146,
+ "y": 216,
"w": 22,
"h": 22
}
},
{
- "filename": "psychic_memory",
+ "filename": "poison_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4329,14 +4287,14 @@
"h": 22
},
"frame": {
- "x": 191,
- "y": 191,
+ "x": 168,
+ "y": 216,
"w": 22,
"h": 22
}
},
{
- "filename": "rock_memory",
+ "filename": "protector",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4350,14 +4308,14 @@
"h": 22
},
"frame": {
- "x": 213,
- "y": 193,
+ "x": 190,
+ "y": 216,
"w": 22,
"h": 22
}
},
{
- "filename": "scroll_of_darkness",
+ "filename": "repel",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4365,20 +4323,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
- "h": 22
+ "x": 8,
+ "y": 4,
+ "w": 16,
+ "h": 24
},
"frame": {
- "x": 257,
- "y": 176,
- "w": 22,
- "h": 22
+ "x": 212,
+ "y": 215,
+ "w": 16,
+ "h": 24
}
},
{
- "filename": "scroll_of_waters",
+ "filename": "psychic_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4392,14 +4350,14 @@
"h": 22
},
"frame": {
- "x": 279,
- "y": 176,
+ "x": 228,
+ "y": 213,
"w": 22,
"h": 22
}
},
{
- "filename": "shed_shell",
+ "filename": "rock_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4413,14 +4371,14 @@
"h": 22
},
"frame": {
- "x": 235,
- "y": 196,
+ "x": 250,
+ "y": 214,
"w": 22,
"h": 22
}
},
{
- "filename": "starf_berry",
+ "filename": "scroll_of_darkness",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4434,14 +4392,14 @@
"h": 22
},
"frame": {
- "x": 301,
- "y": 178,
+ "x": 272,
+ "y": 216,
"w": 22,
"h": 22
}
},
{
- "filename": "steel_memory",
+ "filename": "scroll_of_waters",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4455,14 +4413,14 @@
"h": 22
},
"frame": {
- "x": 323,
- "y": 178,
+ "x": 294,
+ "y": 217,
"w": 22,
"h": 22
}
},
{
- "filename": "sweet_apple",
+ "filename": "shed_shell",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4471,19 +4429,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
+ "y": 5,
"w": 22,
- "h": 21
+ "h": 22
},
"frame": {
- "x": 257,
- "y": 198,
+ "x": 316,
+ "y": 221,
"w": 22,
- "h": 21
+ "h": 22
}
},
{
- "filename": "syrupy_apple",
+ "filename": "starf_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4492,19 +4450,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
+ "y": 5,
"w": 22,
- "h": 21
+ "h": 22
},
"frame": {
- "x": 279,
- "y": 198,
+ "x": 338,
+ "y": 221,
"w": 22,
- "h": 21
+ "h": 22
}
},
{
- "filename": "tart_apple",
+ "filename": "sharp_beak",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4513,19 +4471,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
- "w": 22,
- "h": 21
+ "y": 5,
+ "w": 21,
+ "h": 23
},
"frame": {
- "x": 301,
- "y": 200,
- "w": 22,
- "h": 21
+ "x": 148,
+ "y": 238,
+ "w": 21,
+ "h": 23
}
},
{
- "filename": "thick_club",
+ "filename": "steel_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4539,14 +4497,14 @@
"h": 22
},
"frame": {
- "x": 323,
- "y": 200,
+ "x": 169,
+ "y": 238,
"w": 22,
"h": 22
}
},
{
- "filename": "thunder_stone",
+ "filename": "whipped_dream",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4555,19 +4513,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
- "w": 22,
- "h": 22
+ "y": 4,
+ "w": 21,
+ "h": 23
},
"frame": {
- "x": 129,
- "y": 213,
- "w": 22,
- "h": 22
+ "x": 191,
+ "y": 238,
+ "w": 21,
+ "h": 23
}
},
{
- "filename": "lock_capsule",
+ "filename": "hard_meteorite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4577,18 +4535,18 @@
"spriteSourceSize": {
"x": 7,
"y": 5,
- "w": 19,
+ "w": 20,
"h": 22
},
"frame": {
- "x": 151,
- "y": 213,
- "w": 19,
+ "x": 212,
+ "y": 239,
+ "w": 20,
"h": 22
}
},
{
- "filename": "shiny_stone",
+ "filename": "super_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4596,20 +4554,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 6,
- "w": 21,
- "h": 21
+ "x": 8,
+ "y": 5,
+ "w": 17,
+ "h": 23
},
"frame": {
- "x": 170,
- "y": 210,
- "w": 21,
- "h": 21
+ "x": 232,
+ "y": 235,
+ "w": 17,
+ "h": 23
}
},
{
- "filename": "tera_orb",
+ "filename": "thick_club",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4618,19 +4576,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
+ "y": 5,
"w": 22,
- "h": 20
+ "h": 22
},
"frame": {
- "x": 191,
- "y": 213,
+ "x": 249,
+ "y": 236,
"w": 22,
- "h": 20
+ "h": 22
}
},
{
- "filename": "tm_bug",
+ "filename": "sweet_apple",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4639,19 +4597,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 6,
"w": 22,
- "h": 22
+ "h": 21
},
"frame": {
- "x": 213,
- "y": 215,
+ "x": 271,
+ "y": 238,
"w": 22,
- "h": 22
+ "h": 21
}
},
{
- "filename": "tm_dark",
+ "filename": "syrupy_apple",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4660,19 +4618,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 6,
"w": 22,
- "h": 22
+ "h": 21
},
"frame": {
- "x": 235,
- "y": 218,
+ "x": 293,
+ "y": 239,
"w": 22,
- "h": 22
+ "h": 21
}
},
{
- "filename": "tm_dragon",
+ "filename": "tart_apple",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4681,19 +4639,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 6,
"w": 22,
- "h": 22
+ "h": 21
},
"frame": {
- "x": 257,
- "y": 219,
+ "x": 315,
+ "y": 243,
"w": 22,
- "h": 22
+ "h": 21
}
},
{
- "filename": "tm_electric",
+ "filename": "thunder_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4707,14 +4665,14 @@
"h": 22
},
"frame": {
- "x": 279,
- "y": 219,
+ "x": 337,
+ "y": 243,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_fairy",
+ "filename": "masterpiece_teacup",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4723,19 +4681,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
- "w": 22,
- "h": 22
+ "y": 7,
+ "w": 21,
+ "h": 18
},
"frame": {
- "x": 301,
- "y": 221,
- "w": 22,
- "h": 22
+ "x": 148,
+ "y": 261,
+ "w": 21,
+ "h": 18
}
},
{
- "filename": "tm_fighting",
+ "filename": "tera_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4744,19 +4702,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 5,
+ "y": 6,
"w": 22,
- "h": 22
+ "h": 20
},
"frame": {
- "x": 323,
- "y": 222,
+ "x": 169,
+ "y": 260,
"w": 22,
- "h": 22
+ "h": 20
}
},
{
- "filename": "tm_fire",
+ "filename": "tm_bug",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4770,14 +4728,14 @@
"h": 22
},
"frame": {
- "x": 349,
- "y": 124,
+ "x": 191,
+ "y": 261,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_flying",
+ "filename": "lock_capsule",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4785,20 +4743,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 7,
"y": 5,
- "w": 22,
+ "w": 19,
"h": 22
},
"frame": {
- "x": 131,
- "y": 235,
- "w": 22,
+ "x": 213,
+ "y": 261,
+ "w": 19,
"h": 22
}
},
{
- "filename": "tm_ghost",
+ "filename": "tm_dark",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4812,14 +4770,14 @@
"h": 22
},
"frame": {
- "x": 131,
- "y": 257,
+ "x": 232,
+ "y": 258,
"w": 22,
"h": 22
}
},
{
- "filename": "hyper_potion",
+ "filename": "metronome",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4827,20 +4785,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 7,
"y": 5,
"w": 17,
- "h": 23
+ "h": 22
},
"frame": {
- "x": 153,
- "y": 235,
+ "x": 254,
+ "y": 258,
"w": 17,
- "h": 23
+ "h": 22
}
},
{
- "filename": "zoom_lens",
+ "filename": "tm_dragon",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4849,19 +4807,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 6,
- "w": 21,
- "h": 21
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 170,
- "y": 231,
- "w": 21,
- "h": 21
+ "x": 271,
+ "y": 259,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "tm_grass",
+ "filename": "tm_electric",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4875,14 +4833,14 @@
"h": 22
},
"frame": {
- "x": 191,
- "y": 233,
+ "x": 293,
+ "y": 260,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_ground",
+ "filename": "tm_fairy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4896,14 +4854,14 @@
"h": 22
},
"frame": {
- "x": 213,
- "y": 237,
+ "x": 315,
+ "y": 264,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_ice",
+ "filename": "tm_fighting",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4917,14 +4875,14 @@
"h": 22
},
"frame": {
- "x": 235,
- "y": 240,
+ "x": 337,
+ "y": 265,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_normal",
+ "filename": "tm_fire",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4938,14 +4896,14 @@
"h": 22
},
"frame": {
- "x": 257,
- "y": 241,
+ "x": 366,
+ "y": 131,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_poison",
+ "filename": "tm_flying",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4959,14 +4917,14 @@
"h": 22
},
"frame": {
- "x": 279,
- "y": 241,
+ "x": 388,
+ "y": 134,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_psychic",
+ "filename": "big_nugget",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -4974,20 +4932,41 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
- "y": 5,
- "w": 22,
- "h": 22
+ "x": 6,
+ "y": 6,
+ "w": 20,
+ "h": 20
},
"frame": {
- "x": 301,
- "y": 243,
- "w": 22,
- "h": 22
+ "x": 128,
+ "y": 272,
+ "w": 20,
+ "h": 20
}
},
{
- "filename": "tm_rock",
+ "filename": "metal_alloy",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 6,
+ "y": 7,
+ "w": 21,
+ "h": 19
+ },
+ "frame": {
+ "x": 148,
+ "y": 279,
+ "w": 21,
+ "h": 19
+ }
+ },
+ {
+ "filename": "tm_ghost",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5001,14 +4980,14 @@
"h": 22
},
"frame": {
- "x": 323,
- "y": 244,
+ "x": 169,
+ "y": 280,
"w": 22,
"h": 22
}
},
{
- "filename": "berry_pot",
+ "filename": "tm_grass",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5016,20 +4995,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
+ "x": 5,
"y": 5,
- "w": 18,
+ "w": 22,
"h": 22
},
"frame": {
- "x": 153,
- "y": 258,
- "w": 18,
+ "x": 191,
+ "y": 283,
+ "w": 22,
"h": 22
}
},
{
- "filename": "sitrus_berry",
+ "filename": "metal_coat",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5039,18 +5018,18 @@
"spriteSourceSize": {
"x": 6,
"y": 5,
- "w": 20,
+ "w": 19,
"h": 22
},
"frame": {
- "x": 171,
- "y": 252,
- "w": 20,
+ "x": 213,
+ "y": 283,
+ "w": 19,
"h": 22
}
},
{
- "filename": "tm_steel",
+ "filename": "tm_ground",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5064,14 +5043,14 @@
"h": 22
},
"frame": {
- "x": 191,
- "y": 255,
+ "x": 232,
+ "y": 280,
"w": 22,
"h": 22
}
},
{
- "filename": "tm_water",
+ "filename": "soothe_bell",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5079,20 +5058,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 5,
+ "x": 8,
"y": 5,
- "w": 22,
+ "w": 17,
"h": 22
},
"frame": {
- "x": 213,
- "y": 259,
- "w": 22,
+ "x": 254,
+ "y": 280,
+ "w": 17,
"h": 22
}
},
{
- "filename": "upgrade",
+ "filename": "tm_ice",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5101,19 +5080,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 7,
+ "y": 5,
"w": 22,
- "h": 19
+ "h": 22
},
"frame": {
- "x": 235,
- "y": 262,
+ "x": 271,
+ "y": 281,
"w": 22,
- "h": 19
+ "h": 22
}
},
{
- "filename": "water_memory",
+ "filename": "tm_normal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5127,14 +5106,14 @@
"h": 22
},
"frame": {
- "x": 257,
- "y": 263,
+ "x": 293,
+ "y": 282,
"w": 22,
"h": 22
}
},
{
- "filename": "water_stone",
+ "filename": "tm_poison",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5148,14 +5127,14 @@
"h": 22
},
"frame": {
- "x": 279,
- "y": 263,
+ "x": 315,
+ "y": 286,
"w": 22,
"h": 22
}
},
{
- "filename": "x_accuracy",
+ "filename": "tm_psychic",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5169,14 +5148,14 @@
"h": 22
},
"frame": {
- "x": 301,
- "y": 265,
+ "x": 337,
+ "y": 287,
"w": 22,
"h": 22
}
},
{
- "filename": "x_attack",
+ "filename": "tm_rock",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5190,14 +5169,14 @@
"h": 22
},
"frame": {
- "x": 323,
- "y": 266,
+ "x": 72,
+ "y": 270,
"w": 22,
"h": 22
}
},
{
- "filename": "big_nugget",
+ "filename": "tm_steel",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5205,20 +5184,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 20,
- "h": 20
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 171,
- "y": 274,
- "w": 20,
- "h": 20
+ "x": 72,
+ "y": 292,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "x_defense",
+ "filename": "tm_water",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5232,14 +5211,14 @@
"h": 22
},
"frame": {
- "x": 191,
- "y": 277,
+ "x": 72,
+ "y": 314,
"w": 22,
"h": 22
}
},
{
- "filename": "x_sp_atk",
+ "filename": "water_memory",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5253,14 +5232,14 @@
"h": 22
},
"frame": {
- "x": 213,
- "y": 281,
+ "x": 72,
+ "y": 336,
"w": 22,
"h": 22
}
},
{
- "filename": "x_sp_def",
+ "filename": "water_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5274,14 +5253,14 @@
"h": 22
},
"frame": {
- "x": 235,
- "y": 281,
+ "x": 72,
+ "y": 358,
"w": 22,
"h": 22
}
},
{
- "filename": "x_speed",
+ "filename": "x_accuracy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5295,14 +5274,14 @@
"h": 22
},
"frame": {
- "x": 257,
- "y": 285,
+ "x": 72,
+ "y": 380,
"w": 22,
"h": 22
}
},
{
- "filename": "dawn_stone",
+ "filename": "leftovers",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5310,20 +5289,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 20,
- "h": 21
+ "x": 8,
+ "y": 5,
+ "w": 15,
+ "h": 22
},
"frame": {
- "x": 279,
- "y": 285,
- "w": 20,
- "h": 21
+ "x": 94,
+ "y": 270,
+ "w": 15,
+ "h": 22
}
},
{
- "filename": "metal_alloy",
+ "filename": "big_mushroom",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5332,19 +5311,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 7,
- "w": 21,
+ "y": 6,
+ "w": 19,
"h": 19
},
"frame": {
- "x": 299,
- "y": 287,
- "w": 21,
+ "x": 109,
+ "y": 273,
+ "w": 19,
"h": 19
}
},
{
- "filename": "masterpiece_teacup",
+ "filename": "x_attack",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5353,40 +5332,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 7,
- "w": 21,
- "h": 18
- },
- "frame": {
- "x": 320,
- "y": 288,
- "w": 21,
- "h": 18
- }
- },
- {
- "filename": "sharp_meteorite",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 21,
- "h": 18
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 346,
- "y": 146,
- "w": 21,
- "h": 18
+ "x": 94,
+ "y": 292,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "metal_coat",
+ "filename": "x_defense",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5394,20 +5352,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 5,
"y": 5,
- "w": 19,
+ "w": 22,
"h": 22
},
"frame": {
- "x": 345,
- "y": 164,
- "w": 19,
+ "x": 116,
+ "y": 292,
+ "w": 22,
"h": 22
}
},
{
- "filename": "sachet",
+ "filename": "x_sp_atk",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5415,20 +5373,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 4,
- "w": 18,
- "h": 23
+ "x": 5,
+ "y": 5,
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 345,
- "y": 186,
- "w": 18,
- "h": 23
+ "x": 94,
+ "y": 314,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "potion",
+ "filename": "x_sp_def",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5436,20 +5394,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 5,
"y": 5,
- "w": 17,
- "h": 23
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 345,
- "y": 209,
- "w": 17,
- "h": 23
+ "x": 94,
+ "y": 336,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "super_potion",
+ "filename": "x_speed",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5457,20 +5415,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 5,
"y": 5,
- "w": 17,
- "h": 23
+ "w": 22,
+ "h": 22
},
"frame": {
- "x": 345,
- "y": 232,
- "w": 17,
- "h": 23
+ "x": 116,
+ "y": 314,
+ "w": 22,
+ "h": 22
}
},
{
- "filename": "unknown",
+ "filename": "poison_barb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5478,20 +5436,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 4,
- "w": 16,
- "h": 24
+ "x": 5,
+ "y": 6,
+ "w": 21,
+ "h": 21
},
"frame": {
- "x": 345,
- "y": 255,
- "w": 16,
- "h": 24
+ "x": 94,
+ "y": 358,
+ "w": 21,
+ "h": 21
}
},
{
- "filename": "unremarkable_teacup",
+ "filename": "shiny_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5500,19 +5458,19 @@
},
"spriteSourceSize": {
"x": 5,
- "y": 7,
+ "y": 6,
"w": 21,
- "h": 18
+ "h": 21
},
"frame": {
- "x": 371,
- "y": 138,
+ "x": 116,
+ "y": 336,
"w": 21,
- "h": 18
+ "h": 21
}
},
{
- "filename": "blue_orb",
+ "filename": "sitrus_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5521,19 +5479,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 6,
+ "y": 5,
"w": 20,
- "h": 20
+ "h": 22
},
"frame": {
- "x": 132,
- "y": 279,
+ "x": 94,
+ "y": 379,
"w": 20,
- "h": 20
+ "h": 22
}
},
{
- "filename": "apicot_berry",
+ "filename": "zoom_lens",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5541,20 +5499,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 5,
"y": 6,
- "w": 19,
- "h": 20
+ "w": 21,
+ "h": 21
},
"frame": {
- "x": 152,
- "y": 280,
- "w": 19,
- "h": 20
+ "x": 138,
+ "y": 298,
+ "w": 21,
+ "h": 21
}
},
{
- "filename": "gb",
+ "filename": "sharp_meteorite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5563,19 +5521,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 6,
- "w": 20,
- "h": 20
+ "y": 8,
+ "w": 21,
+ "h": 18
},
"frame": {
- "x": 132,
- "y": 299,
- "w": 20,
- "h": 20
+ "x": 138,
+ "y": 319,
+ "w": 21,
+ "h": 18
}
},
{
- "filename": "magnet",
+ "filename": "upgrade",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5583,20 +5541,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 20,
- "h": 20
+ "x": 5,
+ "y": 7,
+ "w": 22,
+ "h": 19
},
"frame": {
- "x": 132,
- "y": 319,
- "w": 20,
- "h": 20
+ "x": 137,
+ "y": 337,
+ "w": 22,
+ "h": 19
}
},
{
- "filename": "mb",
+ "filename": "dawn_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5607,17 +5565,17 @@
"x": 6,
"y": 6,
"w": 20,
- "h": 20
+ "h": 21
},
"frame": {
- "x": 132,
- "y": 339,
+ "x": 159,
+ "y": 302,
"w": 20,
- "h": 20
+ "h": 21
}
},
{
- "filename": "pb",
+ "filename": "blue_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5631,14 +5589,14 @@
"h": 20
},
"frame": {
- "x": 132,
- "y": 359,
+ "x": 159,
+ "y": 323,
"w": 20,
"h": 20
}
},
{
- "filename": "quick_claw",
+ "filename": "everstone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5647,19 +5605,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 6,
- "w": 19,
- "h": 21
+ "y": 8,
+ "w": 20,
+ "h": 17
},
"frame": {
- "x": 152,
- "y": 300,
- "w": 19,
- "h": 21
+ "x": 159,
+ "y": 343,
+ "w": 20,
+ "h": 17
}
},
{
- "filename": "pb_gold",
+ "filename": "revive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5667,20 +5625,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 20,
- "h": 20
+ "x": 10,
+ "y": 8,
+ "w": 12,
+ "h": 17
},
"frame": {
- "x": 171,
- "y": 294,
- "w": 20,
- "h": 20
+ "x": 179,
+ "y": 302,
+ "w": 12,
+ "h": 17
}
},
{
- "filename": "spell_tag",
+ "filename": "super_repel",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5688,20 +5646,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 6,
- "w": 19,
- "h": 21
+ "x": 8,
+ "y": 4,
+ "w": 16,
+ "h": 24
},
"frame": {
- "x": 152,
- "y": 321,
- "w": 19,
- "h": 21
+ "x": 179,
+ "y": 319,
+ "w": 16,
+ "h": 24
}
},
{
- "filename": "rb",
+ "filename": "candy",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5709,20 +5667,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 6,
- "w": 20,
- "h": 20
+ "x": 7,
+ "y": 11,
+ "w": 18,
+ "h": 18
},
"frame": {
- "x": 171,
- "y": 314,
- "w": 20,
- "h": 20
+ "x": 179,
+ "y": 343,
+ "w": 18,
+ "h": 18
}
},
{
- "filename": "smooth_meteorite",
+ "filename": "unknown",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5730,16 +5688,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 6,
- "w": 20,
- "h": 20
+ "x": 8,
+ "y": 4,
+ "w": 16,
+ "h": 24
},
"frame": {
- "x": 191,
- "y": 299,
- "w": 20,
- "h": 20
+ "x": 360,
+ "y": 157,
+ "w": 16,
+ "h": 24
}
},
{
@@ -5757,14 +5715,14 @@
"h": 24
},
"frame": {
- "x": 152,
- "y": 342,
+ "x": 360,
+ "y": 181,
"w": 16,
"h": 24
}
},
{
- "filename": "everstone",
+ "filename": "quick_claw",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5773,19 +5731,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 8,
- "w": 20,
- "h": 17
+ "y": 6,
+ "w": 19,
+ "h": 21
},
"frame": {
- "x": 191,
- "y": 319,
- "w": 20,
- "h": 17
+ "x": 360,
+ "y": 205,
+ "w": 19,
+ "h": 21
}
},
{
- "filename": "strange_ball",
+ "filename": "candy_jar",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5795,18 +5753,18 @@
"spriteSourceSize": {
"x": 6,
"y": 6,
- "w": 20,
+ "w": 19,
"h": 20
},
"frame": {
- "x": 211,
- "y": 303,
- "w": 20,
+ "x": 360,
+ "y": 226,
+ "w": 19,
"h": 20
}
},
{
- "filename": "ub",
+ "filename": "gb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5820,14 +5778,14 @@
"h": 20
},
"frame": {
- "x": 231,
- "y": 303,
+ "x": 359,
+ "y": 246,
"w": 20,
"h": 20
}
},
{
- "filename": "candy_jar",
+ "filename": "magnet",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5837,39 +5795,18 @@
"spriteSourceSize": {
"x": 6,
"y": 6,
- "w": 19,
+ "w": 20,
"h": 20
},
"frame": {
- "x": 133,
- "y": 379,
- "w": 19,
+ "x": 359,
+ "y": 266,
+ "w": 20,
"h": 20
}
},
{
- "filename": "full_heal",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 32,
- "h": 32
- },
- "spriteSourceSize": {
- "x": 9,
- "y": 4,
- "w": 15,
- "h": 23
- },
- "frame": {
- "x": 152,
- "y": 366,
- "w": 15,
- "h": 23
- }
- },
- {
- "filename": "lum_berry",
+ "filename": "mb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5878,19 +5815,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 7,
+ "y": 6,
"w": 20,
- "h": 19
+ "h": 20
},
"frame": {
- "x": 211,
- "y": 323,
+ "x": 359,
+ "y": 286,
"w": 20,
- "h": 19
+ "h": 20
}
},
{
- "filename": "razor_claw",
+ "filename": "pb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5899,19 +5836,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 7,
+ "y": 6,
"w": 20,
- "h": 19
+ "h": 20
},
"frame": {
- "x": 231,
- "y": 323,
+ "x": 376,
+ "y": 156,
"w": 20,
- "h": 19
+ "h": 20
}
},
{
- "filename": "hard_stone",
+ "filename": "spell_tag",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5919,20 +5856,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 7,
"y": 6,
"w": 19,
- "h": 20
+ "h": 21
},
"frame": {
- "x": 251,
- "y": 307,
+ "x": 396,
+ "y": 156,
"w": 19,
- "h": 20
+ "h": 21
}
},
{
- "filename": "mega_bracelet",
+ "filename": "pb_gold",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5941,19 +5878,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 8,
+ "y": 6,
"w": 20,
- "h": 16
+ "h": 20
},
"frame": {
- "x": 251,
- "y": 327,
+ "x": 376,
+ "y": 176,
"w": 20,
- "h": 16
+ "h": 20
}
},
{
- "filename": "revive",
+ "filename": "hard_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -5961,16 +5898,16 @@
"h": 32
},
"spriteSourceSize": {
- "x": 10,
- "y": 8,
- "w": 12,
- "h": 17
+ "x": 6,
+ "y": 6,
+ "w": 19,
+ "h": 20
},
"frame": {
- "x": 133,
- "y": 399,
- "w": 12,
- "h": 17
+ "x": 396,
+ "y": 177,
+ "w": 19,
+ "h": 20
}
},
{
@@ -5988,35 +5925,35 @@
"h": 20
},
"frame": {
- "x": 270,
- "y": 307,
+ "x": 379,
+ "y": 196,
"w": 17,
"h": 20
}
},
{
- "filename": "white_herb",
+ "filename": "miracle_seed",
"rotated": false,
"trimmed": true,
"sourceSize": {
- "w": 24,
- "h": 24
+ "w": 32,
+ "h": 32
},
"spriteSourceSize": {
- "x": 2,
- "y": 3,
- "w": 20,
+ "x": 6,
+ "y": 7,
+ "w": 19,
"h": 19
},
"frame": {
- "x": 287,
- "y": 306,
- "w": 20,
+ "x": 396,
+ "y": 197,
+ "w": 19,
"h": 19
}
},
{
- "filename": "miracle_seed",
+ "filename": "rb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6025,19 +5962,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 7,
- "w": 19,
- "h": 19
+ "y": 6,
+ "w": 20,
+ "h": 20
},
"frame": {
- "x": 307,
- "y": 306,
- "w": 19,
- "h": 19
+ "x": 379,
+ "y": 216,
+ "w": 20,
+ "h": 20
}
},
{
- "filename": "leftovers",
+ "filename": "abomasite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6046,19 +5983,40 @@
},
"spriteSourceSize": {
"x": 8,
- "y": 5,
- "w": 15,
- "h": 22
+ "y": 8,
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 326,
- "y": 306,
- "w": 15,
- "h": 22
+ "x": 399,
+ "y": 216,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "abomasite",
+ "filename": "smooth_meteorite",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 7,
+ "y": 6,
+ "w": 20,
+ "h": 20
+ },
+ "frame": {
+ "x": 379,
+ "y": 236,
+ "w": 20,
+ "h": 20
+ }
+ },
+ {
+ "filename": "absolite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6072,14 +6030,14 @@
"h": 16
},
"frame": {
- "x": 271,
- "y": 327,
+ "x": 399,
+ "y": 232,
"w": 16,
"h": 16
}
},
{
- "filename": "wl_ability_urge",
+ "filename": "aerodactylite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6087,20 +6045,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 8,
- "w": 20,
- "h": 18
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 287,
- "y": 325,
- "w": 20,
- "h": 18
+ "x": 399,
+ "y": 248,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "candy",
+ "filename": "strange_ball",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6108,20 +6066,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 11,
- "w": 18,
- "h": 18
+ "x": 6,
+ "y": 6,
+ "w": 20,
+ "h": 20
},
"frame": {
- "x": 307,
- "y": 325,
- "w": 18,
- "h": 18
+ "x": 379,
+ "y": 256,
+ "w": 20,
+ "h": 20
}
},
{
- "filename": "absolite",
+ "filename": "aggronite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6135,14 +6093,14 @@
"h": 16
},
"frame": {
- "x": 325,
- "y": 328,
+ "x": 399,
+ "y": 264,
"w": 16,
"h": 16
}
},
{
- "filename": "wl_antidote",
+ "filename": "ub",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6151,19 +6109,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 8,
+ "y": 6,
"w": 20,
- "h": 18
+ "h": 20
},
"frame": {
- "x": 171,
- "y": 334,
+ "x": 379,
+ "y": 276,
"w": 20,
- "h": 18
+ "h": 20
}
},
{
- "filename": "wl_awakening",
+ "filename": "alakazite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6171,20 +6129,41 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 8,
- "w": 20,
+ "w": 16,
+ "h": 16
+ },
+ "frame": {
+ "x": 399,
+ "y": 280,
+ "w": 16,
+ "h": 16
+ }
+ },
+ {
+ "filename": "unremarkable_teacup",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 32,
+ "h": 32
+ },
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 7,
+ "w": 21,
"h": 18
},
"frame": {
- "x": 191,
- "y": 336,
- "w": 20,
+ "x": 379,
+ "y": 296,
+ "w": 21,
"h": 18
}
},
{
- "filename": "wl_burn_heal",
+ "filename": "eviolite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6192,20 +6171,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 8,
- "w": 20,
- "h": 18
+ "w": 15,
+ "h": 15
},
"frame": {
- "x": 211,
- "y": 342,
- "w": 20,
- "h": 18
+ "x": 400,
+ "y": 296,
+ "w": 15,
+ "h": 15
}
},
{
- "filename": "wl_custom_spliced",
+ "filename": "prism_scale",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6213,20 +6192,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 9,
"y": 8,
- "w": 20,
- "h": 18
+ "w": 15,
+ "h": 15
},
"frame": {
- "x": 231,
- "y": 342,
- "w": 20,
- "h": 18
+ "x": 400,
+ "y": 311,
+ "w": 15,
+ "h": 15
}
},
{
- "filename": "wl_custom_thief",
+ "filename": "lum_berry",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6235,19 +6214,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 8,
+ "y": 7,
"w": 20,
- "h": 18
+ "h": 19
},
"frame": {
- "x": 251,
- "y": 343,
+ "x": 359,
+ "y": 306,
"w": 20,
- "h": 18
+ "h": 19
}
},
{
- "filename": "wl_elixir",
+ "filename": "mega_bracelet",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6258,17 +6237,17 @@
"x": 6,
"y": 8,
"w": 20,
- "h": 18
+ "h": 16
},
"frame": {
- "x": 271,
- "y": 343,
+ "x": 379,
+ "y": 314,
"w": 20,
- "h": 18
+ "h": 16
}
},
{
- "filename": "wl_ether",
+ "filename": "altarianite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6276,20 +6255,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
+ "x": 8,
"y": 8,
- "w": 20,
- "h": 18
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 291,
- "y": 343,
- "w": 20,
- "h": 18
+ "x": 399,
+ "y": 326,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "wl_full_heal",
+ "filename": "razor_claw",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6298,19 +6277,19 @@
},
"spriteSourceSize": {
"x": 6,
- "y": 8,
+ "y": 7,
"w": 20,
- "h": 18
+ "h": 19
},
"frame": {
- "x": 168,
- "y": 352,
+ "x": 195,
+ "y": 305,
"w": 20,
- "h": 18
+ "h": 19
}
},
{
- "filename": "wl_full_restore",
+ "filename": "oval_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6318,20 +6297,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
- "h": 18
+ "x": 7,
+ "y": 7,
+ "w": 18,
+ "h": 19
},
"frame": {
- "x": 167,
- "y": 370,
- "w": 20,
- "h": 18
+ "x": 195,
+ "y": 324,
+ "w": 18,
+ "h": 19
}
},
{
- "filename": "wl_guard_spec",
+ "filename": "lucky_egg",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6339,20 +6318,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
- "h": 18
+ "x": 7,
+ "y": 6,
+ "w": 17,
+ "h": 20
},
"frame": {
- "x": 188,
- "y": 354,
- "w": 20,
- "h": 18
+ "x": 215,
+ "y": 305,
+ "w": 17,
+ "h": 20
}
},
{
- "filename": "wl_hyper_potion",
+ "filename": "razor_fang",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6360,20 +6339,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
- "h": 18
+ "x": 7,
+ "y": 6,
+ "w": 18,
+ "h": 20
},
"frame": {
- "x": 187,
- "y": 372,
- "w": 20,
- "h": 18
+ "x": 232,
+ "y": 302,
+ "w": 18,
+ "h": 20
}
},
{
- "filename": "wl_ice_heal",
+ "filename": "wl_ability_urge",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6387,14 +6366,14 @@
"h": 18
},
"frame": {
- "x": 208,
- "y": 360,
+ "x": 250,
+ "y": 302,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_item_drop",
+ "filename": "wl_antidote",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6408,14 +6387,14 @@
"h": 18
},
"frame": {
- "x": 228,
- "y": 360,
+ "x": 270,
+ "y": 303,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_item_urge",
+ "filename": "wl_awakening",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6429,14 +6408,14 @@
"h": 18
},
"frame": {
- "x": 248,
- "y": 361,
+ "x": 213,
+ "y": 325,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_max_elixir",
+ "filename": "wl_burn_heal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6450,14 +6429,14 @@
"h": 18
},
"frame": {
- "x": 268,
- "y": 361,
+ "x": 197,
+ "y": 343,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_max_ether",
+ "filename": "dark_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6465,20 +6444,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
+ "x": 7,
+ "y": 7,
+ "w": 18,
"h": 18
},
"frame": {
- "x": 288,
- "y": 361,
- "w": 20,
+ "x": 217,
+ "y": 343,
+ "w": 18,
"h": 18
}
},
{
- "filename": "wl_max_potion",
+ "filename": "wl_custom_spliced",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6492,14 +6471,14 @@
"h": 18
},
"frame": {
- "x": 207,
- "y": 378,
+ "x": 290,
+ "y": 304,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_max_revive",
+ "filename": "flame_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6507,20 +6486,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
+ "x": 7,
+ "y": 7,
+ "w": 18,
"h": 18
},
"frame": {
- "x": 227,
- "y": 378,
- "w": 20,
+ "x": 233,
+ "y": 322,
+ "w": 18,
"h": 18
}
},
{
- "filename": "wl_paralyze_heal",
+ "filename": "light_ball",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6528,20 +6507,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 6,
- "y": 8,
- "w": 20,
+ "x": 7,
+ "y": 7,
+ "w": 18,
"h": 18
},
"frame": {
- "x": 247,
- "y": 379,
- "w": 20,
+ "x": 251,
+ "y": 320,
+ "w": 18,
"h": 18
}
},
{
- "filename": "wl_potion",
+ "filename": "wl_custom_thief",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6555,14 +6534,14 @@
"h": 18
},
"frame": {
- "x": 267,
- "y": 379,
+ "x": 269,
+ "y": 321,
"w": 20,
"h": 18
}
},
{
- "filename": "wl_reset_urge",
+ "filename": "wl_elixir",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6576,14 +6555,14 @@
"h": 18
},
"frame": {
- "x": 287,
- "y": 379,
+ "x": 289,
+ "y": 322,
"w": 20,
"h": 18
}
},
{
- "filename": "metronome",
+ "filename": "light_stone",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6592,19 +6571,19 @@
},
"spriteSourceSize": {
"x": 7,
- "y": 5,
- "w": 17,
- "h": 22
+ "y": 7,
+ "w": 18,
+ "h": 18
},
"frame": {
- "x": 341,
- "y": 288,
- "w": 17,
- "h": 22
+ "x": 235,
+ "y": 340,
+ "w": 18,
+ "h": 18
}
},
{
- "filename": "soothe_bell",
+ "filename": "ampharosite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6613,19 +6592,19 @@
},
"spriteSourceSize": {
"x": 8,
- "y": 5,
- "w": 17,
- "h": 22
+ "y": 8,
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 341,
- "y": 310,
- "w": 17,
- "h": 22
+ "x": 253,
+ "y": 338,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "dark_stone",
+ "filename": "wl_ether",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6633,20 +6612,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
+ "x": 6,
+ "y": 8,
+ "w": 20,
"h": 18
},
"frame": {
- "x": 341,
- "y": 332,
- "w": 18,
+ "x": 269,
+ "y": 339,
+ "w": 20,
"h": 18
}
},
{
- "filename": "aerodactylite",
+ "filename": "wl_full_heal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6654,20 +6633,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 152,
- "y": 389,
- "w": 16,
- "h": 16
+ "x": 289,
+ "y": 340,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "flame_orb",
+ "filename": "wl_full_restore",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6675,20 +6654,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
+ "x": 6,
+ "y": 8,
+ "w": 20,
"h": 18
},
"frame": {
- "x": 168,
- "y": 388,
- "w": 18,
+ "x": 310,
+ "y": 308,
+ "w": 20,
"h": 18
}
},
{
- "filename": "wl_revive",
+ "filename": "wl_guard_spec",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6702,14 +6681,14 @@
"h": 18
},
"frame": {
- "x": 186,
- "y": 390,
+ "x": 309,
+ "y": 326,
"w": 20,
"h": 18
}
},
{
- "filename": "razor_fang",
+ "filename": "wl_hyper_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6717,20 +6696,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 6,
- "w": 18,
- "h": 20
+ "x": 6,
+ "y": 8,
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 206,
- "y": 396,
- "w": 18,
- "h": 20
+ "x": 309,
+ "y": 344,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "lucky_egg",
+ "filename": "wl_ice_heal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6738,20 +6717,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 6,
- "w": 17,
- "h": 20
+ "x": 6,
+ "y": 8,
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 224,
- "y": 396,
- "w": 17,
- "h": 20
+ "x": 330,
+ "y": 309,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "oval_stone",
+ "filename": "wl_item_drop",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6759,20 +6738,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
- "h": 19
+ "x": 6,
+ "y": 8,
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 241,
- "y": 397,
- "w": 18,
- "h": 19
+ "x": 329,
+ "y": 327,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "wl_super_potion",
+ "filename": "wl_item_urge",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6786,14 +6765,14 @@
"h": 18
},
"frame": {
- "x": 259,
- "y": 397,
+ "x": 329,
+ "y": 345,
"w": 20,
"h": 18
}
},
{
- "filename": "light_ball",
+ "filename": "audinite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6801,20 +6780,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
- "h": 18
+ "x": 8,
+ "y": 8,
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 279,
- "y": 397,
- "w": 18,
- "h": 18
+ "x": 253,
+ "y": 354,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "light_stone",
+ "filename": "wl_max_elixir",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6822,20 +6801,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
+ "x": 6,
+ "y": 8,
+ "w": 20,
"h": 18
},
"frame": {
- "x": 297,
- "y": 397,
- "w": 18,
+ "x": 269,
+ "y": 357,
+ "w": 20,
"h": 18
}
},
{
- "filename": "mystery_egg",
+ "filename": "wl_max_ether",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6843,20 +6822,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
+ "w": 20,
"h": 18
},
"frame": {
- "x": 307,
- "y": 379,
- "w": 16,
+ "x": 289,
+ "y": 358,
+ "w": 20,
"h": 18
}
},
{
- "filename": "toxic_orb",
+ "filename": "wl_max_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6864,20 +6843,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 7,
- "w": 18,
+ "x": 6,
+ "y": 8,
+ "w": 20,
"h": 18
},
"frame": {
- "x": 308,
- "y": 361,
- "w": 18,
+ "x": 309,
+ "y": 362,
+ "w": 20,
"h": 18
}
},
{
- "filename": "aggronite",
+ "filename": "wl_max_revive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6885,20 +6864,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 315,
- "y": 397,
- "w": 16,
- "h": 16
+ "x": 329,
+ "y": 363,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "eviolite",
+ "filename": "toxic_orb",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6906,20 +6885,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 8,
- "w": 15,
- "h": 15
+ "x": 7,
+ "y": 7,
+ "w": 18,
+ "h": 18
},
"frame": {
- "x": 326,
- "y": 344,
- "w": 15,
- "h": 15
+ "x": 235,
+ "y": 358,
+ "w": 18,
+ "h": 18
}
},
{
- "filename": "prism_scale",
+ "filename": "banettite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6927,20 +6906,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 9,
+ "x": 8,
"y": 8,
- "w": 15,
- "h": 15
+ "w": 16,
+ "h": 16
},
"frame": {
- "x": 311,
- "y": 344,
- "w": 15,
- "h": 15
+ "x": 253,
+ "y": 370,
+ "w": 16,
+ "h": 16
}
},
{
- "filename": "alakazite",
+ "filename": "wl_paralyze_heal",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6948,20 +6927,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 326,
- "y": 359,
- "w": 16,
- "h": 16
+ "x": 269,
+ "y": 375,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "relic_band",
+ "filename": "wl_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6969,20 +6948,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 7,
- "y": 9,
- "w": 17,
- "h": 16
+ "x": 6,
+ "y": 8,
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 342,
- "y": 350,
- "w": 17,
- "h": 16
+ "x": 289,
+ "y": 376,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "altarianite",
+ "filename": "wl_reset_urge",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -6990,20 +6969,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 342,
- "y": 366,
- "w": 16,
- "h": 16
+ "x": 309,
+ "y": 380,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "ampharosite",
+ "filename": "wl_revive",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7011,20 +6990,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 326,
- "y": 375,
- "w": 16,
- "h": 16
+ "x": 329,
+ "y": 381,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "audinite",
+ "filename": "wl_super_potion",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7032,20 +7011,20 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
+ "x": 6,
"y": 8,
- "w": 16,
- "h": 16
+ "w": 20,
+ "h": 18
},
"frame": {
- "x": 342,
- "y": 382,
- "w": 16,
- "h": 16
+ "x": 116,
+ "y": 357,
+ "w": 20,
+ "h": 18
}
},
{
- "filename": "banettite",
+ "filename": "relic_band",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7053,15 +7032,15 @@
"h": 32
},
"spriteSourceSize": {
- "x": 8,
- "y": 8,
- "w": 16,
+ "x": 7,
+ "y": 9,
+ "w": 17,
"h": 16
},
"frame": {
- "x": 367,
- "y": 156,
- "w": 16,
+ "x": 115,
+ "y": 375,
+ "w": 17,
"h": 16
}
},
@@ -7080,8 +7059,8 @@
"h": 16
},
"frame": {
- "x": 364,
- "y": 172,
+ "x": 114,
+ "y": 391,
"w": 16,
"h": 16
}
@@ -7101,8 +7080,8 @@
"h": 16
},
"frame": {
- "x": 363,
- "y": 188,
+ "x": 130,
+ "y": 399,
"w": 16,
"h": 16
}
@@ -7122,8 +7101,8 @@
"h": 16
},
"frame": {
- "x": 363,
- "y": 204,
+ "x": 146,
+ "y": 399,
"w": 16,
"h": 16
}
@@ -7143,8 +7122,8 @@
"h": 16
},
"frame": {
- "x": 362,
- "y": 220,
+ "x": 162,
+ "y": 399,
"w": 16,
"h": 16
}
@@ -7164,14 +7143,14 @@
"h": 16
},
"frame": {
- "x": 362,
- "y": 236,
+ "x": 178,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "candy_overlay",
+ "filename": "charizardite_y",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7180,19 +7159,19 @@
},
"spriteSourceSize": {
"x": 8,
- "y": 12,
+ "y": 8,
"w": 16,
- "h": 15
+ "h": 16
},
"frame": {
- "x": 331,
- "y": 398,
+ "x": 194,
+ "y": 399,
"w": 16,
- "h": 15
+ "h": 16
}
},
{
- "filename": "charizardite_y",
+ "filename": "diancite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7206,14 +7185,14 @@
"h": 16
},
"frame": {
- "x": 347,
- "y": 398,
+ "x": 210,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "diancite",
+ "filename": "galladite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7227,14 +7206,14 @@
"h": 16
},
"frame": {
- "x": 380,
- "y": 172,
+ "x": 226,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "galladite",
+ "filename": "garchompite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7248,14 +7227,14 @@
"h": 16
},
"frame": {
- "x": 379,
- "y": 188,
+ "x": 242,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "garchompite",
+ "filename": "gardevoirite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7269,14 +7248,14 @@
"h": 16
},
"frame": {
- "x": 379,
- "y": 204,
+ "x": 258,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "gardevoirite",
+ "filename": "gengarite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7290,14 +7269,14 @@
"h": 16
},
"frame": {
- "x": 378,
- "y": 220,
+ "x": 274,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "gengarite",
+ "filename": "glalitite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7311,14 +7290,14 @@
"h": 16
},
"frame": {
- "x": 378,
- "y": 236,
+ "x": 290,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "glalitite",
+ "filename": "gyaradosite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7332,14 +7311,14 @@
"h": 16
},
"frame": {
- "x": 362,
- "y": 252,
+ "x": 306,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "gyaradosite",
+ "filename": "heracronite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7353,14 +7332,14 @@
"h": 16
},
"frame": {
- "x": 378,
- "y": 252,
+ "x": 322,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "heracronite",
+ "filename": "houndoominite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7374,14 +7353,14 @@
"h": 16
},
"frame": {
- "x": 361,
- "y": 268,
+ "x": 338,
+ "y": 399,
"w": 16,
"h": 16
}
},
{
- "filename": "houndoominite",
+ "filename": "kangaskhanite",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7395,14 +7374,14 @@
"h": 16
},
"frame": {
- "x": 377,
- "y": 268,
+ "x": 132,
+ "y": 375,
"w": 16,
"h": 16
}
},
{
- "filename": "kangaskhanite",
+ "filename": "candy_overlay",
"rotated": false,
"trimmed": true,
"sourceSize": {
@@ -7411,15 +7390,15 @@
},
"spriteSourceSize": {
"x": 8,
- "y": 8,
+ "y": 12,
"w": 16,
- "h": 16
+ "h": 15
},
"frame": {
- "x": 358,
- "y": 284,
+ "x": 136,
+ "y": 360,
"w": 16,
- "h": 16
+ "h": 15
}
},
{
@@ -7437,8 +7416,8 @@
"h": 16
},
"frame": {
- "x": 358,
- "y": 300,
+ "x": 152,
+ "y": 360,
"w": 16,
"h": 16
}
@@ -7458,8 +7437,8 @@
"h": 16
},
"frame": {
- "x": 358,
- "y": 316,
+ "x": 148,
+ "y": 376,
"w": 16,
"h": 16
}
@@ -7479,8 +7458,8 @@
"h": 16
},
"frame": {
- "x": 374,
- "y": 284,
+ "x": 168,
+ "y": 361,
"w": 16,
"h": 16
}
@@ -7500,8 +7479,8 @@
"h": 16
},
"frame": {
- "x": 374,
- "y": 300,
+ "x": 184,
+ "y": 361,
"w": 16,
"h": 16
}
@@ -7521,8 +7500,8 @@
"h": 16
},
"frame": {
- "x": 374,
- "y": 316,
+ "x": 200,
+ "y": 361,
"w": 16,
"h": 16
}
@@ -7542,8 +7521,8 @@
"h": 16
},
"frame": {
- "x": 359,
- "y": 332,
+ "x": 216,
+ "y": 361,
"w": 16,
"h": 16
}
@@ -7563,8 +7542,8 @@
"h": 16
},
"frame": {
- "x": 359,
- "y": 348,
+ "x": 164,
+ "y": 377,
"w": 16,
"h": 16
}
@@ -7584,8 +7563,8 @@
"h": 16
},
"frame": {
- "x": 375,
- "y": 332,
+ "x": 180,
+ "y": 377,
"w": 16,
"h": 16
}
@@ -7605,8 +7584,8 @@
"h": 16
},
"frame": {
- "x": 375,
- "y": 348,
+ "x": 196,
+ "y": 377,
"w": 16,
"h": 16
}
@@ -7626,8 +7605,8 @@
"h": 16
},
"frame": {
- "x": 390,
- "y": 284,
+ "x": 212,
+ "y": 377,
"w": 16,
"h": 16
}
@@ -7647,8 +7626,8 @@
"h": 16
},
"frame": {
- "x": 390,
- "y": 300,
+ "x": 228,
+ "y": 377,
"w": 16,
"h": 16
}
@@ -7668,8 +7647,8 @@
"h": 16
},
"frame": {
- "x": 390,
- "y": 316,
+ "x": 349,
+ "y": 327,
"w": 16,
"h": 16
}
@@ -7689,8 +7668,8 @@
"h": 16
},
"frame": {
- "x": 391,
- "y": 332,
+ "x": 349,
+ "y": 343,
"w": 16,
"h": 16
}
@@ -7710,8 +7689,8 @@
"h": 16
},
"frame": {
- "x": 391,
- "y": 348,
+ "x": 349,
+ "y": 359,
"w": 16,
"h": 16
}
@@ -7731,8 +7710,8 @@
"h": 16
},
"frame": {
- "x": 393,
- "y": 268,
+ "x": 349,
+ "y": 375,
"w": 16,
"h": 16
}
@@ -7752,8 +7731,8 @@
"h": 16
},
"frame": {
- "x": 359,
- "y": 364,
+ "x": 354,
+ "y": 391,
"w": 16,
"h": 16
}
@@ -7773,8 +7752,8 @@
"h": 16
},
"frame": {
- "x": 375,
- "y": 364,
+ "x": 365,
+ "y": 330,
"w": 16,
"h": 16
}
@@ -7794,8 +7773,8 @@
"h": 16
},
"frame": {
- "x": 391,
- "y": 364,
+ "x": 381,
+ "y": 330,
"w": 16,
"h": 16
}
@@ -7815,8 +7794,8 @@
"h": 16
},
"frame": {
- "x": 358,
- "y": 380,
+ "x": 365,
+ "y": 346,
"w": 16,
"h": 16
}
@@ -7836,8 +7815,8 @@
"h": 16
},
"frame": {
- "x": 374,
- "y": 380,
+ "x": 365,
+ "y": 362,
"w": 16,
"h": 16
}
@@ -7857,8 +7836,8 @@
"h": 16
},
"frame": {
- "x": 390,
- "y": 380,
+ "x": 381,
+ "y": 346,
"w": 16,
"h": 16
}
@@ -7878,8 +7857,8 @@
"h": 16
},
"frame": {
- "x": 363,
- "y": 396,
+ "x": 381,
+ "y": 362,
"w": 16,
"h": 16
}
@@ -7899,8 +7878,8 @@
"h": 16
},
"frame": {
- "x": 379,
- "y": 396,
+ "x": 397,
+ "y": 342,
"w": 16,
"h": 16
}
@@ -7920,8 +7899,8 @@
"h": 16
},
"frame": {
- "x": 395,
- "y": 396,
+ "x": 397,
+ "y": 358,
"w": 16,
"h": 16
}
@@ -7941,8 +7920,8 @@
"h": 16
},
"frame": {
- "x": 396,
- "y": 158,
+ "x": 397,
+ "y": 374,
"w": 16,
"h": 16
}
@@ -7962,8 +7941,8 @@
"h": 16
},
"frame": {
- "x": 396,
- "y": 174,
+ "x": 370,
+ "y": 378,
"w": 16,
"h": 16
}
@@ -7974,6 +7953,6 @@
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:8d494b572ffc237a0b6482a3c2b0958e:bce8aa90c95f0da5ffad5b6de5eaf4ed:110e074689c9edd2c54833ce2e4d9270$"
+ "smartupdate": "$TexturePacker:SmartUpdate:60db8f4653a650759cd9189e91c38a40:439307cbef9c000f6c45603b2d82d107:110e074689c9edd2c54833ce2e4d9270$"
}
}
diff --git a/public/images/items.png b/public/images/items.png
index e6ee07d6b107..6d9434d04541 100644
Binary files a/public/images/items.png and b/public/images/items.png differ
diff --git a/public/images/items/white_herb.png b/public/images/items/white_herb.png
deleted file mode 100644
index 25cfc6521091..000000000000
Binary files a/public/images/items/white_herb.png and /dev/null differ
diff --git a/public/images/mystery-encounters/chest_blue.json b/public/images/mystery-encounters/chest_blue.json
deleted file mode 100644
index 88aadda845ad..000000000000
--- a/public/images/mystery-encounters/chest_blue.json
+++ /dev/null
@@ -1,188 +0,0 @@
-{
- "textures": [
- {
- "image": "chest_blue.png",
- "format": "RGBA8888",
- "size": {
- "w": 300,
- "h": 75
- },
- "scale": 1,
- "frames": [
- {
- "filename": "0001.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": -15,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0002.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": -15,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0003.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 57,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0004.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 57,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0005.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 129,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0006.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 129,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0007.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 201,
- "y": 0,
- "w": 75,
- "h": 75
- }
- },
- {
- "filename": "0008.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 75,
- "h": 75
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 75,
- "h": 75
- },
- "frame": {
- "x": 201,
- "y": 0,
- "w": 75,
- "h": 75
- }
- }
- ]
- }
- ],
- "meta": {
- "app": "https://www.codeandweb.com/texturepacker",
- "version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:895f0a79b89fa0fb44167f4584fd9a22:357b46953b7e17c6b2f43a62d52855d8:cc1ed0e4f90aaa9dcf1b39a0af1283b0$"
- }
-}
diff --git a/public/images/mystery-encounters/chest_blue.png b/public/images/mystery-encounters/chest_blue.png
deleted file mode 100644
index 0097346e845a..000000000000
Binary files a/public/images/mystery-encounters/chest_blue.png and /dev/null differ
diff --git a/public/images/mystery-encounters/chest_red.json b/public/images/mystery-encounters/chest_red.json
deleted file mode 100644
index d808652a1621..000000000000
--- a/public/images/mystery-encounters/chest_red.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "textures": [
- {
- "image": "chest_red.png",
- "format": "RGBA8888",
- "size": {
- "w": 76,
- "h": 57
- },
- "scale": 1,
- "frames": [
- {
- "filename": "0001.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 76,
- "h": 57
- },
- "spriteSourceSize": {
- "x": 10,
- "y": 3,
- "w": 56,
- "h": 54
- },
- "frame": {
- "x": 8,
- "y": 0,
- "w": 56,
- "h": 54
- }
- }
- ]
- }
- ],
- "meta": {
- "app": "https://www.codeandweb.com/texturepacker",
- "version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:895f0a79b89fa0fb44167f4584fd9a22:357b46953b7e17c6b2f43a62d52855d8:cc1ed0e4f90aaa9dcf1b39a0af1283b0$"
- }
-}
diff --git a/public/images/mystery-encounters/chest_red.png b/public/images/mystery-encounters/chest_red.png
deleted file mode 100644
index e9ccfa2cfc6a..000000000000
Binary files a/public/images/mystery-encounters/chest_red.png and /dev/null differ
diff --git a/public/images/mystery-encounters/dark_deal_porygon.json b/public/images/mystery-encounters/dark_deal_porygon.json
deleted file mode 100644
index 5a48d95c18d4..000000000000
--- a/public/images/mystery-encounters/dark_deal_porygon.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "textures": [
- {
- "image": "dark_deal_porygon.png",
- "format": "RGBA8888",
- "size": {
- "w": 36,
- "h": 45
- },
- "scale": 1,
- "frames": [
- {
- "filename": "0001.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 36,
- "h": 45
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 44,
- "h": 44
- },
- "frame": {
- "x": 0,
- "y": 0,
- "w": 36,
- "h": 45
- }
- }
- ]
- }
- ],
- "meta": {
- "app": "https://www.codeandweb.com/texturepacker",
- "version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:895f0a79b89fa0fb44167f4584fd9a22:357b46953b7e17c6b2f43a62d52855d8:cc1ed0e4f90aaa9dcf1b39a0af1283b0$"
- }
-}
diff --git a/public/images/mystery-encounters/dark_deal_porygon.png b/public/images/mystery-encounters/dark_deal_porygon.png
deleted file mode 100644
index 168999fb0f46..000000000000
Binary files a/public/images/mystery-encounters/dark_deal_porygon.png and /dev/null differ
diff --git a/public/images/mystery-encounters/mad_scientist_m.json b/public/images/mystery-encounters/mad_scientist_m.json
deleted file mode 100644
index 0cb3f904cb0b..000000000000
--- a/public/images/mystery-encounters/mad_scientist_m.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "textures": [
- {
- "image": "mad_scientist_m.png",
- "format": "RGBA8888",
- "size": {
- "w": 44,
- "h": 74
- },
- "scale": 1,
- "frames": [
- {
- "filename": "0001.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 44,
- "h": 74
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 44,
- "h": 74
- },
- "frame": {
- "x": 0,
- "y": 0,
- "w": 44,
- "h": 74
- }
- }
- ]
- }
- ],
- "meta": {
- "app": "https://www.codeandweb.com/texturepacker",
- "version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:895f0a79b89fa0fb44167f4584fd9a22:357b46953b7e17c6b2f43a62d52855d8:cc1ed0e4f90aaa9dcf1b39a0af1283b0$"
- }
-}
diff --git a/public/images/mystery-encounters/mad_scientist_m.png b/public/images/mystery-encounters/mad_scientist_m.png
deleted file mode 100644
index 84349b46c8a9..000000000000
Binary files a/public/images/mystery-encounters/mad_scientist_m.png and /dev/null differ
diff --git a/public/images/mystery-encounters/training_gear.json b/public/images/mystery-encounters/training_gear.json
deleted file mode 100644
index fb8f4ec9c8ea..000000000000
--- a/public/images/mystery-encounters/training_gear.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "textures": [
- {
- "image": "training_gear.png",
- "format": "RGBA8888",
- "size": {
- "w": 76,
- "h": 57
- },
- "scale": 1,
- "frames": [
- {
- "filename": "0001.png",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 76,
- "h": 57
- },
- "spriteSourceSize": {
- "x": 10,
- "y": 3,
- "w": 56,
- "h": 54
- },
- "frame": {
- "x": 8,
- "y": 0,
- "w": 56,
- "h": 54
- }
- }
- ]
- }
- ],
- "meta": {
- "app": "https://www.codeandweb.com/texturepacker",
- "version": "3.0",
- "smartupdate": "$TexturePacker:SmartUpdate:895f0a79b89fa0fb44167f4584fd9a22:357b46953b7e17c6b2f43a62d52855d8:cc1ed0e4f90aaa9dcf1b39a0af1283b0$"
- }
-}
diff --git a/public/images/mystery-encounters/training_gear.png b/public/images/mystery-encounters/training_gear.png
deleted file mode 100644
index 42c3a9bb7d4e..000000000000
Binary files a/public/images/mystery-encounters/training_gear.png and /dev/null differ
diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json
index a956f81150d4..b7da47fc1921 100644
--- a/public/images/ui/legacy/pbinfo_stat.json
+++ b/public/images/ui/legacy/pbinfo_stat.json
@@ -176,27 +176,6 @@
"w": 12,
"h": 6
}
- },
- {
- "filename": "HP",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 9,
- "h": 8
- },
- "spriteSourceSize": {
- "x": 1,
- "y": 2,
- "w": 8,
- "h": 6
- },
- "frame": {
- "x": 112,
- "y": 0,
- "w": 8,
- "h": 6
- }
}
]
}
diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png
index 18b0ca314dec..62ec3758772d 100644
Binary files a/public/images/ui/legacy/pbinfo_stat.png and b/public/images/ui/legacy/pbinfo_stat.png differ
diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json
index c106d1cf41eb..fa7d757990ff 100644
--- a/public/images/ui/legacy/pbinfo_stat_numbers.json
+++ b/public/images/ui/legacy/pbinfo_stat_numbers.json
@@ -281,27 +281,6 @@
"w": 9,
"h": 8
}
- },
- {
- "filename": "empty",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 1,
- "h": 8
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 1,
- "h": 8
- },
- "frame": {
- "x": 117,
- "y": 0,
- "w": 1,
- "h": 8
- }
}
]
}
diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png
index b02dfbec72f6..ee1453b21070 100644
Binary files a/public/images/ui/legacy/pbinfo_stat_numbers.png and b/public/images/ui/legacy/pbinfo_stat_numbers.png differ
diff --git a/public/images/ui/pbinfo_stat.json b/public/images/ui/pbinfo_stat.json
index 4ec46c467b13..f431e5afafd6 100644
--- a/public/images/ui/pbinfo_stat.json
+++ b/public/images/ui/pbinfo_stat.json
@@ -176,27 +176,6 @@
"w": 13,
"h": 7
}
- },
- {
- "filename": "HP",
- "rotated": false,
- "trimmed": true,
- "sourceSize": {
- "w": 9,
- "h": 8
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 1,
- "w": 9,
- "h": 7
- },
- "frame": {
- "x": 120,
- "y": 0,
- "w": 9,
- "h": 7
- }
}
]
}
diff --git a/public/images/ui/pbinfo_stat.png b/public/images/ui/pbinfo_stat.png
index 1c20ed70e821..46169091e7cd 100644
Binary files a/public/images/ui/pbinfo_stat.png and b/public/images/ui/pbinfo_stat.png differ
diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json
index ccd49bbbb79b..ec4f7117bb72 100644
--- a/public/images/ui/pbinfo_stat_numbers.json
+++ b/public/images/ui/pbinfo_stat_numbers.json
@@ -281,27 +281,6 @@
"w": 9,
"h": 8
}
- },
- {
- "filename": "empty",
- "rotated": false,
- "trimmed": false,
- "sourceSize": {
- "w": 1,
- "h": 8
- },
- "spriteSourceSize": {
- "x": 0,
- "y": 0,
- "w": 1,
- "h": 8
- },
- "frame": {
- "x": 117,
- "y": 0,
- "w": 1,
- "h": 8
- }
}
]
}
diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png
index 1465f8b7a649..c778ba992734 100644
Binary files a/public/images/ui/pbinfo_stat_numbers.png and b/public/images/ui/pbinfo_stat_numbers.png differ
diff --git a/src/battle-scene.ts b/src/battle-scene.ts
index a3f74eafc8b2..ba0720baab23 100644
--- a/src/battle-scene.ts
+++ b/src/battle-scene.ts
@@ -3,25 +3,9 @@ import UI from "./ui/ui";
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
-import {Constructor, isNullOrUndefined} from "#app/utils";
+import { Constructor } from "#app/utils";
import * as Utils from "./utils";
-import {
- Modifier,
- ModifierBar,
- ConsumablePokemonModifier,
- ConsumableModifier,
- PokemonHpRestoreModifier,
- HealingBoosterModifier,
- PersistentModifier,
- PokemonHeldItemModifier,
- ModifierPredicate,
- DoubleBattleChanceBoosterModifier,
- FusePokemonModifier,
- PokemonFormChangeItemModifier,
- TerastallizeModifier,
- overrideModifiers,
- overrideHeldItems
-} from "./modifier/modifier";
+import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball";
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
import { Phase } from "./phase";
@@ -30,16 +14,7 @@ import { Arena, ArenaBase } from "./field/arena";
import { GameData } from "./system/game-data";
import { TextStyle, addTextObject, getTextColor } from "./ui/text";
import { allMoves } from "./data/move";
-import {
- ModifierPoolType,
- getDefaultModifierTypeForTier,
- getEnemyModifierTypesForWave,
- getLuckString,
- getLuckTextTint,
- getModifierPoolForType,
- getPartyLuckValue,
- PokemonHeldItemModifierType
-} from "./modifier/modifier-type";
+import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue } from "./modifier/modifier-type";
import AbilityBar from "./ui/ability-bar";
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, PostBattleInitAbAttr, applyAbAttrs, applyPostBattleInitAbAttrs } from "./data/ability";
import { allAbilities } from "./data/ability";
@@ -92,15 +67,6 @@ import { Species } from "#enums/species";
import { UiTheme } from "#enums/ui-theme";
import { TimedEventManager } from "#app/timed-event-manager.js";
import i18next from "i18next";
-import MysteryEncounter, { MysteryEncounterTier, MysteryEncounterVariant } from "./data/mystery-encounter";
-import {
- mysteryEncountersByBiome,
- allMysteryEncounters,
- BASE_MYSTERY_ENCOUNTER_WEIGHT,
- AVERAGE_ENCOUNTERS_PER_RUN_TARGET
-} from "./data/mystery-encounters/mystery-encounters";
-import {MysteryEncounterFlags} from "#app/data/mystery-encounter-flags";
-import { MysteryEncounterType } from "#enums/mystery-encounter-type";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@@ -153,7 +119,6 @@ export default class BattleScene extends SceneBase {
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableMoveInfo: boolean = true;
public enableRetries: boolean = false;
- public hideIvs: boolean = false;
/**
* Determines the condition for a notification should be shown for Candy Upgrades
* - 0 = 'Off'
@@ -214,21 +179,11 @@ export default class BattleScene extends SceneBase {
public gameData: GameData;
public sessionSlotId: integer;
- /**
- * queues are moved around during the function shiftPhase() below
- * can debug phases using "phase.constructor.name"
- */
-
- /** PhaseQueue: dequeue/remove the first element to get the next phase */
public phaseQueue: Phase[];
public conditionalQueue: Array<[() => boolean, Phase]>;
- /** PhaseQueuePrepend: is a temp storage of what will be added to PhaseQueue */
private phaseQueuePrepend: Phase[];
-
- /** overrides default of inserting phases to end of phaseQueuePrepend array, useful or inserting Phases "out of order" */
private phaseQueuePrependSpliceIndex: integer;
private nextCommandPhaseQueue: Phase[];
-
private currentPhase: Phase;
private standbyPhase: Phase;
public field: Phaser.GameObjects.Container;
@@ -268,9 +223,6 @@ export default class BattleScene extends SceneBase {
private fieldOverlay: Phaser.GameObjects.Rectangle;
private shopOverlay: Phaser.GameObjects.Rectangle;
- private shopOverlayShown: boolean = false;
- private shopOverlayOpacity: number = .80;
-
public modifiers: PersistentModifier[];
private enemyModifiers: PersistentModifier[];
public uiContainer: Phaser.GameObjects.Container;
@@ -301,9 +253,6 @@ export default class BattleScene extends SceneBase {
public eventManager: TimedEventManager;
- public mysteryEncounterFlags: MysteryEncounterFlags = new MysteryEncounterFlags(null);
- public lastMysteryEncounter: MysteryEncounter;
-
/**
* Allows subscribers to listen for events
*
@@ -867,20 +816,6 @@ export default class BattleScene extends SceneBase {
return pokemon;
}
- removePokemonFromPlayerParty(pokemon: PlayerPokemon, destroy: boolean = true) {
- if (!pokemon) {
- return;
- }
-
- const partyIndex = this.party.indexOf(pokemon);
- this.party.splice(partyIndex, 1);
- if (destroy) {
- this.field.remove(pokemon, true);
- pokemon.destroy();
- }
- this.updateModifiers(true);
- }
-
addPokemonIcon(pokemon: Pokemon, x: number, y: number, originX: number = 0.5, originY: number = 0.5, ignoreOverride: boolean = false): Phaser.GameObjects.Container {
const container = this.add.container(x, y);
container.setName(`${pokemon.name}-icon`);
@@ -1071,7 +1006,7 @@ export default class BattleScene extends SceneBase {
}
}
- newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean, mysteryEncounter?: MysteryEncounter): Battle {
+ newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle {
const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave;
const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1);
let newDouble: boolean;
@@ -1115,37 +1050,6 @@ export default class BattleScene extends SceneBase {
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, doubleTrainer ? TrainerVariant.DOUBLE : Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
this.field.add(newTrainer);
}
-
- // Check for mystery encounter
- // Can only occur in place of a standard wild battle, waves 10-180
- // let testStartingWeight = 10;
- // while (testStartingWeight < 30) {
- // calculateMEAggregateStats(this, testStartingWeight);
- // testStartingWeight += 2;
- // }
- if (this.gameMode.hasMysteryEncounters && newBattleType === BattleType.WILD && !this.gameMode.isBoss(newWaveIndex) && newWaveIndex < 180 && newWaveIndex > 10) {
- const roll = Utils.randSeedInt(256);
-
- // Base spawn weight is 3/256, and increases by 1/256 for each missed attempt at spawning an encounter on a valid floor
- const sessionEncounterRate = !isNullOrUndefined(this.mysteryEncounterFlags?.encounterSpawnChance) ? this.mysteryEncounterFlags.encounterSpawnChance : BASE_MYSTERY_ENCOUNTER_WEIGHT;
-
- // If total number of encounters is lower than expected for the run, slightly favor a new encounter spawn
- // Do the reverse as well
- // Reduces occurrence of runs with very few (<6) and a ton (>10) of encounters
- const expectedEncountersByFloor = AVERAGE_ENCOUNTERS_PER_RUN_TARGET / (180 - 10) * newWaveIndex;
- const currentRunDiffFromAvg = expectedEncountersByFloor - (this.mysteryEncounterFlags?.encounteredEvents?.length || 0);
- const favoredEncounterRate = sessionEncounterRate + currentRunDiffFromAvg * 5;
-
- const successRate = isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE) ? favoredEncounterRate : Overrides.MYSTERY_ENCOUNTER_RATE_OVERRIDE;
-
- if (roll < successRate) {
- newBattleType = BattleType.MYSTERY_ENCOUNTER;
- // Reset base spawn weight
- this.mysteryEncounterFlags.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_WEIGHT;
- } else {
- this.mysteryEncounterFlags.encounterSpawnChance = sessionEncounterRate + 1;
- }
- }
}
if (double === undefined && newWaveIndex > 1) {
@@ -1178,19 +1082,12 @@ export default class BattleScene extends SceneBase {
const maxExpLevel = this.getMaxExpLevel();
this.lastEnemyTrainer = lastBattle?.trainer ?? null;
- this.lastMysteryEncounter = lastBattle?.mysteryEncounter ?? null;
this.executeWithSeedOffset(() => {
this.currentBattle = new Battle(this.gameMode, newWaveIndex, newBattleType, newTrainer, newDouble);
}, newWaveIndex << 3, this.waveSeed);
this.currentBattle.incrementTurn(this);
- if (newBattleType === BattleType.MYSTERY_ENCOUNTER) {
- // Disable double battle on mystery encounters (it may be re-enabled as part of encounter)
- this.currentBattle.double = false;
- this.currentBattle.mysteryEncounter = this.getMysteryEncounter(mysteryEncounter);
- }
-
//this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6));
if (!waveIndex && lastBattle) {
@@ -1215,9 +1112,7 @@ export default class BattleScene extends SceneBase {
isNewBiome = !Utils.randSeedInt(6 - biomeWaves);
}, lastBattle.waveIndex << 4);
}
-
-
- const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
+ const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS;
this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
this.trySpreadPokerus();
if (!isNewBiome && (newWaveIndex % 10) === 5) {
@@ -1225,24 +1120,17 @@ export default class BattleScene extends SceneBase {
}
if (resetArenaState) {
this.arena.removeAllTags();
- // If last battle was mystery encounter and no battle occurred, skip return phases
- if (lastBattle?.mysteryEncounter?.encounterVariant !== MysteryEncounterVariant.NO_BATTLE) {
- playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
- for (const pokemon of this.getParty()) {
- // Only trigger form change when Eiscue is in Noice form
- // Hardcoded Eiscue for now in case it is fused with another pokemon
- if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
- this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
- }
- // Only trigger form change when Mimikyu is in Busted form
- // Hardcoded Mimikyu for now in case it is fused with another pokemon
- if (pokemon.species.speciesId === Species.MIMIKYU && pokemon.hasAbility(Abilities.DISGUISE) && pokemon.formIndex === 1) {
- this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
- }
+ playerField.forEach((_, p) => this.unshiftPhase(new ReturnPhase(this, p)));
- pokemon.resetBattleData();
- applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
+ for (const pokemon of this.getParty()) {
+ // Only trigger form change when Eiscue is in Noice form
+ // Hardcoded Eiscue for now in case it is fused with another pokemon
+ if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
+ this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
}
+
+ pokemon.resetBattleData();
+ applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
}
this.unshiftPhase(new ShowTrainerPhase(this));
@@ -1534,29 +1422,19 @@ export default class BattleScene extends SceneBase {
});
}
- updateShopOverlayOpacity(value: number): void {
- this.shopOverlayOpacity = value;
-
- if (this.shopOverlayShown) {
- this.shopOverlay.setAlpha(this.shopOverlayOpacity);
- }
- }
-
showShopOverlay(duration: integer): Promise {
- this.shopOverlayShown = true;
return new Promise(resolve => {
this.tweens.add({
targets: this.shopOverlay,
- alpha: this.shopOverlayOpacity,
+ alpha: 0.8,
ease: "Sine.easeOut",
- duration,
+ duration: duration,
onComplete: () => resolve()
});
});
}
hideShopOverlay(duration: integer): Promise {
- this.shopOverlayShown = false;
return new Promise(resolve => {
this.tweens.add({
targets: this.shopOverlay,
@@ -2064,12 +1942,6 @@ export default class BattleScene extends SceneBase {
return this.standbyPhase;
}
- /**
- * PhaseQueuePrepend: is a temp storage of what will be added to PhaseQueue
- * PhaseQueue: dequeue/remove the first element to get the next phase
- * queues are moved around during shiftPhase() below
- */
-
/**
* Adds a phase to the conditional queue and ensures it is executed only when the specified condition is met.
*
@@ -2084,64 +1956,31 @@ export default class BattleScene extends SceneBase {
this.conditionalQueue.push([condition, phase]);
}
- /**
- * Adds a phase to nextCommandPhaseQueue, as long as boolean passed in is false
- * @param phase {@linkcode Phase} the phase to add
- * @param defer boolean on which queue to add to, defaults to false, and adds to phaseQueue
- */
+
pushPhase(phase: Phase, defer: boolean = false): void {
(!defer ? this.phaseQueue : this.nextCommandPhaseQueue).push(phase);
}
- /**
- * Adds Phase to the end of phaseQueuePrepend, or at phaseQueuePrependSpliceIndex
- * @param phase {@linkcode Phase} the phase to add
- */
unshiftPhase(phase: Phase): void {
if (this.phaseQueuePrependSpliceIndex === -1) {
- // .push() adds to end of array
this.phaseQueuePrepend.push(phase);
} else {
- // .splice(index, num elements to remove, what to add)
- // modifies array by inserting at index, removing num of elements after index
this.phaseQueuePrepend.splice(this.phaseQueuePrependSpliceIndex, 0, phase);
}
- /**
- * debugging queues via printing, may be helpful in the future
- console.log(`State of the phaseQueuePrepend (will be moved over to phaseQeueu)`)
- this.phaseQueuePrepend.forEach(p => console.log(p.constructor.name));
-
- console.log(`State of the phaseQueue, what is going to be called next `)
- this.phaseQueue.forEach(p => console.log(p.constructor.name));
- */
}
- /**
- * Clears phaseQueue
- */
clearPhaseQueue(): void {
this.phaseQueue.splice(0, this.phaseQueue.length);
}
- /**
- * combo with unshiftPhase(), want to start inserting at current length instead of the "end", useful if phaseQueuePrepend gets longer with Phases
- */
setPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = this.phaseQueuePrepend.length;
}
- /**
- * Resets phaseQueuePrependSpliceIndex to -1, implies that calls to unshiftPhase will insert at end of phaseQueuePrepend
- */
clearPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = -1;
}
- /**
- * is called by each Phase implementations "end()" by default
- * dumps everything from phaseQueuePrepend to the start of of phaseQueue
- * then removes first Phase and starts it
- */
shiftPhase(): void {
if (this.standbyPhase) {
this.currentPhase = this.standbyPhase;
@@ -2149,21 +1988,14 @@ export default class BattleScene extends SceneBase {
return;
}
- // shifting phase (with no standby phase) will move everything from prepend to actual PhaseQueue?
- // resets the index, if it was changed via setPhaseQueueSplice()
if (this.phaseQueuePrependSpliceIndex > -1) {
this.clearPhaseQueueSplice();
}
if (this.phaseQueuePrepend.length) {
while (this.phaseQueuePrepend.length) {
- // appends phaseQueuePrepend to phaseQueue
- // eg: phaseQueue = [4,5,6], phaseQUeuePrepend = [1,2,3]
- // -> [1,2,3,4,5,6]
this.phaseQueue.unshift(this.phaseQueuePrepend.pop());
}
}
- // then starts from PhaseQueue, .shift() removes first elm of array
- // populatePhaseQueue() adds a turnInit Phase at the end of phaseQueue (if the queue is emtpy)
if (!this.phaseQueue.length) {
this.populatePhaseQueue();
// clear the conditionalQueue if there are no phases left in the phaseQueue
@@ -2233,28 +2065,15 @@ export default class BattleScene extends SceneBase {
}
}
- /**
- * Adds a MessagePhase, either to PhaseQueuePrepend or nextCommandPhaseQueue
- * @param message string for MessagePhase
- * @param callbackDelay optional param for MessagePhase constructor
- * @param prompt optional param for MessagePhase constructor
- * @param promptDelay optional param for MessagePhase constructor
- * @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue
- */
queueMessage(message: string, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer, defer?: boolean) {
const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay);
if (!defer) {
- // adds to the end of PhaseQueuePrepend
this.unshiftPhase(phase);
} else {
- //remember that pushPhase adds it to nextCommandPhaseQueue
this.pushPhase(phase);
}
}
- /**
- * Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
- */
populatePhaseQueue(): void {
if (this.nextCommandPhaseQueue.length) {
this.phaseQueue.push(...this.nextCommandPhaseQueue);
@@ -2456,7 +2275,7 @@ export default class BattleScene extends SceneBase {
});
}
- generateEnemyModifiers(customHeldModifiers?: PokemonHeldItemModifierType[][]): Promise {
+ generateEnemyModifiers(): Promise {
return new Promise(resolve => {
if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
return resolve();
@@ -2478,33 +2297,29 @@ export default class BattleScene extends SceneBase {
}
party.forEach((enemyPokemon: EnemyPokemon, i: integer) => {
- if (customHeldModifiers && i < customHeldModifiers.length && customHeldModifiers[i].length > 0) {
- customHeldModifiers[i].forEach(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
- } else {
- const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss);
- let upgradeChance = 32;
- if (isBoss) {
- upgradeChance /= 2;
- }
- if (isFinalBoss) {
- upgradeChance /= 8;
- }
- const modifierChance = this.gameMode.getEnemyModifierChance(isBoss);
- let pokemonModifierChance = modifierChance;
- if (this.currentBattle.battleType === BattleType.TRAINER)
- pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line
- let count = 0;
- for (let c = 0; c < chances; c++) {
- if (!Utils.randSeedInt(modifierChance)) {
- count++;
- }
- }
- if (isBoss) {
- count = Math.max(count, Math.floor(chances / 2));
+ const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss);
+ let upgradeChance = 32;
+ if (isBoss) {
+ upgradeChance /= 2;
+ }
+ if (isFinalBoss) {
+ upgradeChance /= 8;
+ }
+ const modifierChance = this.gameMode.getEnemyModifierChance(isBoss);
+ let pokemonModifierChance = modifierChance;
+ if (this.currentBattle.battleType === BattleType.TRAINER)
+ pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line
+ let count = 0;
+ for (let c = 0; c < chances; c++) {
+ if (!Utils.randSeedInt(modifierChance)) {
+ count++;
}
- getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance)
- .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
}
+ if (isBoss) {
+ count = Math.max(count, Math.floor(chances / 2));
+ }
+ getEnemyModifierTypesForWave(difficultyWaveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, upgradeChance)
+ .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
});
this.updateModifiers(false).then(() => resolve());
@@ -2726,88 +2541,4 @@ export default class BattleScene extends SceneBase {
};
(window as any).gameInfo = gameInfo;
}
-
- /**
- * Loads or generates a mystery encounter
- * @param override - used to load session encounter when restarting game, etc.
- * @returns
- */
- getMysteryEncounter(override: MysteryEncounter): MysteryEncounter {
- // Loading override or session encounter
- let encounter: MysteryEncounter;
- if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_OVERRIDE) && allMysteryEncounters.hasOwnProperty(Overrides.MYSTERY_ENCOUNTER_OVERRIDE)) {
- encounter = allMysteryEncounters[Overrides.MYSTERY_ENCOUNTER_OVERRIDE];
- } else {
- encounter = override?.encounterType >= 0 ? allMysteryEncounters[override?.encounterType] : null;
- }
-
- // Check for queued encounters first
- if (!encounter && this.mysteryEncounterFlags?.nextEncounterQueue?.length > 0) {
- let i = 0;
- while (i < this.mysteryEncounterFlags.nextEncounterQueue.length && !!encounter) {
- const candidate = this.mysteryEncounterFlags.nextEncounterQueue[i];
- const forcedChance = candidate[1];
- if (Utils.randSeedInt(100) < forcedChance) {
- encounter = allMysteryEncounters[candidate[0]];
- }
-
- i++;
- }
- }
-
- if (encounter) {
- encounter = new MysteryEncounter(encounter);
- encounter.meetsRequirements(this);
- return encounter;
- }
-
- // Common / Uncommon / Rare / Super Rare
- const tierWeights = [61, 40, 21, 6];
-
- // Adjust tier weights by previously encountered events to lower odds of only common/uncommons in run
- this.mysteryEncounterFlags.encounteredEvents.forEach(val => {
- const tier = val[1];
- if (tier === MysteryEncounterTier.COMMON) {
- tierWeights[0] = tierWeights[0] - 6;
- } else if (tier === MysteryEncounterTier.UNCOMMON) {
- tierWeights[1] = tierWeights[1] - 4;
- }
- });
-
- const totalWeight = tierWeights.reduce((a, b) => a + b);
- const tierValue = Utils.randSeedInt(totalWeight);
- const commonThreshold = totalWeight - tierWeights[0];
- const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1];
- const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2];
- let tier = tierValue > commonThreshold ? MysteryEncounterTier.COMMON : tierValue > uncommonThreshold ? MysteryEncounterTier.UNCOMMON : tierValue > rareThreshold ? MysteryEncounterTier.RARE : MysteryEncounterTier.SUPER_RARE;
-
- if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE)) {
- tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
- }
-
- let availableEncounters = [];
- // New encounter will never be the same as the most recent encounter
- const previousEncounter = this.mysteryEncounterFlags.encounteredEvents?.length > 0 ? this.mysteryEncounterFlags.encounteredEvents[this.mysteryEncounterFlags.encounteredEvents.length - 1][0] : null;
- const biomeMysteryEncounters = mysteryEncountersByBiome.get(this.arena.biomeType);
- // If no valid encounters exist at tier, checks next tier down, continuing until there are some encounters available
- while (availableEncounters.length === 0 && tier >= 0) {
- availableEncounters = biomeMysteryEncounters
- .filter((encounterType) =>
- allMysteryEncounters[encounterType]?.meetsRequirements(this) &&
- allMysteryEncounters[encounterType].encounterTier === tier &&
- (isNullOrUndefined(previousEncounter) || encounterType !== previousEncounter))
- .map((m) => (allMysteryEncounters[m]));
- tier--;
- }
-
- // If absolutely no encounters are available, spawn 0th encounter
- if (availableEncounters.length === 0) {
- return allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS];
- }
- encounter = availableEncounters[Utils.randSeedInt(availableEncounters.length)];
- // New encounter object to not dirty flags
- encounter = new MysteryEncounter(encounter);
- encounter.meetsRequirements(this);
- return encounter;
- }
}
diff --git a/src/battle.ts b/src/battle.ts
index ec61596131eb..c3a481e9956d 100644
--- a/src/battle.ts
+++ b/src/battle.ts
@@ -13,34 +13,32 @@ import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type";
-import MysteryEncounter, { MysteryEncounterVariant } from "./data/mystery-encounter";
export enum BattleType {
- WILD,
- TRAINER,
- CLEAR,
- MYSTERY_ENCOUNTER
+ WILD,
+ TRAINER,
+ CLEAR
}
export enum BattlerIndex {
- ATTACKER = -1,
- PLAYER,
- PLAYER_2,
- ENEMY,
- ENEMY_2
+ ATTACKER = -1,
+ PLAYER,
+ PLAYER_2,
+ ENEMY,
+ ENEMY_2
}
export interface TurnCommand {
- command: Command;
- cursor?: integer;
- move?: QueuedMove;
- targets?: BattlerIndex[];
- skip?: boolean;
- args?: any[];
+ command: Command;
+ cursor?: integer;
+ move?: QueuedMove;
+ targets?: BattlerIndex[];
+ skip?: boolean;
+ args?: any[];
}
interface TurnCommands {
- [key: integer]: TurnCommand
+ [key: integer]: TurnCommand
}
export default class Battle {
@@ -68,7 +66,6 @@ export default class Battle {
public lastUsedPokeball: PokeballType;
public playerFaints: number; // The amount of times pokemon on the players side have fainted
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
- public mysteryEncounter: MysteryEncounter;
private rngCounter: integer = 0;
@@ -107,7 +104,7 @@ export default class Battle {
this.battleSpec = spec;
}
- public getLevelForWave(): integer {
+ private getLevelForWave(): integer {
const levelWaveIndex = this.gameMode.getWaveForDifficulty(this.waveIndex);
const baseLevel = 1 + levelWaveIndex / 2 + Math.pow(levelWaveIndex / 25, 2);
const bossMultiplier = 1.2;
@@ -201,7 +198,7 @@ export default class Battle {
getBgmOverride(scene: BattleScene): string {
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
- if (this.battleType === BattleType.TRAINER || this.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
+ if (this.battleType === BattleType.TRAINER) {
if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length) {
return `encounter_${this.trainer.getEncounterBgm()}`;
}
diff --git a/src/data/ability.ts b/src/data/ability.ts
index 16c2f9b0456a..f449b33992bf 100644
--- a/src/data/ability.ts
+++ b/src/data/ability.ts
@@ -245,6 +245,25 @@ export class PreDefendAbAttr extends AbAttr {
}
}
+export class PreDefendFormChangeAbAttr extends PreDefendAbAttr {
+ private formFunc: (p: Pokemon) => integer;
+
+ constructor(formFunc: ((p: Pokemon) => integer)) {
+ super(true);
+
+ this.formFunc = formFunc;
+ }
+
+ applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
+ const formIndex = this.formFunc(pokemon);
+ if (formIndex !== pokemon.formIndex) {
+ pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
+ return true;
+ }
+
+ return false;
+ }
+}
export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (pokemon.hp === pokemon.getMaxHp() &&
@@ -308,6 +327,21 @@ export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultip
}
}
+export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
+ constructor(condition: PokemonDefendCondition) {
+ super(condition, 1);
+ }
+
+ applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
+ if (this.condition(pokemon, attacker, move)) {
+ (args[0] as Utils.NumberHolder).value = Math.floor(pokemon.getMaxHp() / 8);
+ return true;
+ }
+
+ return false;
+ }
+}
+
/**
* Determines whether a Pokemon is immune to a move because of an ability.
* @extends PreDefendAbAttr
@@ -456,6 +490,45 @@ export class PostDefendAbAttr extends AbAttr {
}
}
+export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {
+
+ applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
+ if (pokemon.formIndex === 0 && pokemon.battleData.hitCount !== 0 && (move.category === MoveCategory.SPECIAL || move.category === MoveCategory.PHYSICAL)) {
+
+ const recoilDamage = Math.ceil((pokemon.getMaxHp() / 8) - attacker.turnData.damageDealt);
+ if (!recoilDamage) {
+ return false;
+ }
+ pokemon.damageAndUpdate(recoilDamage, HitResult.OTHER);
+ pokemon.turnData.damageTaken += recoilDamage;
+ pokemon.scene.queueMessage(getPokemonMessage(pokemon, "'s disguise was busted!"));
+ return true;
+ }
+
+ return false;
+ }
+}
+
+export class PostDefendFormChangeAbAttr extends PostDefendAbAttr {
+ private formFunc: (p: Pokemon) => integer;
+
+ constructor(formFunc: ((p: Pokemon) => integer)) {
+ super(true);
+
+ this.formFunc = formFunc;
+ }
+
+ applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
+ const formIndex = this.formFunc(pokemon);
+ if (formIndex !== pokemon.formIndex) {
+ pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
+ return true;
+ }
+
+ return false;
+ }
+}
+
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const attackPriority = new Utils.IntegerHolder(move.priority);
@@ -2048,50 +2121,6 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
}
}
-/**
- * Removes supplied status effects from the user's field.
- */
-export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAttr {
- private statusEffect: StatusEffect[];
-
- /**
- *
- * @param statusEffect - The status effects to be removed from the user's field.
- */
- constructor(...statusEffect: StatusEffect[]) {
- super(false);
-
- this.statusEffect = statusEffect;
- }
-
- /**
- * Applies the post-summon ability.
- *
- * @param pokemon - The Pokémon that triggered the ability.
- * @param passive - Whether the ability is applied passively.
- * @param args - Additional arguments for the ability.
- * @returns A boolean or a promise that resolves to a boolean indicating the result of the ability application.
- */
- applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise {
- const field = pokemon.getAlliedField();
- const allowedParty = field.filter(p => p.isAllowedInBattle());
-
- if (allowedParty.length < 1) {
- return false;
- }
-
- for (const pokemon of allowedParty) {
- if (this.statusEffect.includes(pokemon.status?.effect)) {
- pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
- pokemon.resetStatus(false);
- pokemon.updateInfo();
- }
- }
-
- return true;
- }
-}
-
/** Attempt to copy the stat changes on an ally pokemon */
export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr {
@@ -2339,33 +2368,17 @@ export class PreSetStatusAbAttr extends AbAttr {
}
}
-/**
- * Provides immunity to status effects to specified targets.
- */
-export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
+export class StatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
private immuneEffects: StatusEffect[];
- /**
- * @param immuneEffects - The status effects to which the Pokémon is immune.
- */
constructor(...immuneEffects: StatusEffect[]) {
super();
this.immuneEffects = immuneEffects;
}
- /**
- * Applies a pre-set status to a Pokémon.
- *
- * @param pokemon - The Pokémon to which the status is being applied.
- * @param passive - Whether the status is applied passively.
- * @param effect - The status effect being applied.
- * @param cancelled - A holder for a boolean value indicating if the status application was cancelled.
- * @param args - Additional arguments for the status application.
- * @returns A boolean indicating the result of the status application.
- */
applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean {
- if (this.immuneEffects.length < 1 || this.immuneEffects.includes(effect)) {
+ if (!this.immuneEffects.length || this.immuneEffects.indexOf(effect) > -1) {
cancelled.value = true;
return true;
}
@@ -2378,31 +2391,14 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
}
}
-/**
- * Provides immunity to status effects to the user.
- * @extends PreSetStatusEffectImmunityAbAttr
- */
-export class StatusEffectImmunityAbAttr extends PreSetStatusEffectImmunityAbAttr { }
-
-/**
- * Provides immunity to status effects to the user's field.
- * @extends PreSetStatusEffectImmunityAbAttr
- */
-export class UserFieldStatusEffectImmunityAbAttr extends PreSetStatusEffectImmunityAbAttr { }
-
export class PreApplyBattlerTagAbAttr extends AbAttr {
applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise {
return false;
}
}
-/**
- * Provides immunity to BattlerTags {@linkcode BattlerTag} to specified targets.
- * @extends PreApplyBattlerTagAbAttr
- */
-export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
+export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
private immuneTagType: BattlerTagType;
- private battlerTag: BattlerTag;
constructor(immuneTagType: BattlerTagType) {
super();
@@ -2413,7 +2409,6 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (tag.tagType === this.immuneTagType) {
cancelled.value = true;
- this.battlerTag = tag;
return true;
}
@@ -2421,22 +2416,10 @@ export class PreApplyBattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
}
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
- return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents ${this.battlerTag.getDescriptor()}!`);
+ return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents ${(args[0] as BattlerTag).getDescriptor()}!`);
}
}
-/**
- * Provides immunity to BattlerTags {@linkcode BattlerTag} to the user.
- * @extends PreApplyBattlerTagImmunityAbAttr
- */
-export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr { }
-
-/**
- * Provides immunity to BattlerTags {@linkcode BattlerTag} to the user's field.
- * @extends PreApplyBattlerTagImmunityAbAttr
- */
-export class UserFieldBattlerTagImmunityAbAttr extends PreApplyBattlerTagImmunityAbAttr { }
-
export class BlockCritAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
(args[0] as Utils.BooleanHolder).value = true;
@@ -3891,54 +3874,6 @@ export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAt
}
}
-/**
- * Takes no damage from the first hit of a damaging move.
- * This is used in the Disguise ability.
- */
-export class DisguiseBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
- private multiplier: number;
-
- constructor(condition: PokemonDefendCondition, multiplier: number) {
- super(condition, multiplier);
-
- this.multiplier = multiplier;
- }
-
- /**
- * Applies the Disguise pre-defense ability to the Pokémon.
- * Removes BattlerTagType.DISGUISE when hit by an attack and is in its Disguised form.
- *
- * @param {Pokemon} pokemon - The Pokémon with the Disguise ability.
- * @param {boolean} passive - Whether the ability is passive.
- * @param {Pokemon} attacker - The attacking Pokémon.
- * @param {PokemonMove} move - The move being used.
- * @param {Utils.BooleanHolder} cancelled - A holder for whether the move was cancelled.
- * @param {any[]} args - Additional arguments.
- * @returns {boolean} - Whether the immunity was applied.
- */
- applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
- if (this.condition(pokemon, attacker, move)) {
- (args[0] as Utils.NumberHolder).value = this.multiplier;
- pokemon.removeTag(BattlerTagType.DISGUISE);
- pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 8), HitResult.OTHER);
- return true;
- }
-
- return false;
- }
-
- /**
- * Gets the message triggered when the Pokémon avoids damage using the Disguise ability.
- * @param {Pokemon} pokemon - The Pokémon with the Disguise ability.
- * @param {string} abilityName - The name of the ability.
- * @param {...any} args - Additional arguments.
- * @returns {string} - The trigger message.
- */
- getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
- return i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonName: pokemon.name, abilityName: abilityName });
- }
-}
-
/**
* If a Pokémon with this Ability selects a damaging move, it has a 30% chance of going first in its priority bracket. If the Ability activates, this is announced at the start of the turn (after move selection).
*
@@ -3987,42 +3922,47 @@ export class BypassSpeedChanceAbAttr extends AbAttr {
}
}
-async function applyAbAttrsInternal(
- attrType: Constructor,
- pokemon: Pokemon,
- applyFunc: AbAttrApplyFunc,
- args: any[],
- showAbilityInstant: boolean = false,
- quiet: boolean = false,
-) {
- for (const passive of [false, true]) {
+function applyAbAttrsInternal(attrType: Constructor,
+ pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise {
+ return new Promise(resolve => {
if (!pokemon.canApplyAbility(passive)) {
- continue;
- }
-
- const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
- for (const attr of ability.getAttrs(attrType)) {
- const condition = attr.getCondition();
- if (condition && !condition(pokemon)) {
- continue;
+ if (!passive) {
+ return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
+ } else {
+ return resolve();
}
+ }
- pokemon.scene.setPhaseQueueSplice();
+ const ability = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility());
+ const attrs = ability.getAttrs(attrType);
- let result = applyFunc(attr, passive);
- // TODO Remove this when promises get reworked PR#924
- if (result instanceof Promise) {
- result = await result;
+ const clearSpliceQueueAndResolve = () => {
+ pokemon.scene?.clearPhaseQueueSplice();
+ if (!passive) {
+ return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve());
+ } else {
+ return resolve();
}
-
- if (result) {
+ };
+ const applyNextAbAttr = () => {
+ if (attrs.length) {
+ applyAbAttr(attrs.shift());
+ } else {
+ clearSpliceQueueAndResolve();
+ }
+ };
+ const applyAbAttr = (attr: TAttr) => {
+ if (!canApplyAttr(pokemon, attr)) {
+ return applyNextAbAttr();
+ }
+ pokemon.scene.setPhaseQueueSplice();
+ const onApplySuccess = () => {
if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) {
pokemon.summonData.abilitiesApplied.push(ability.id);
}
if (pokemon.battleData && !pokemon.battleData.abilitiesApplied.includes(ability.id)) {
pokemon.battleData.abilitiesApplied.push(ability.id);
}
-
if (attr.showAbility && !quiet) {
if (showAbilityInstant) {
pokemon.scene.abilityBar.showAbility(pokemon, passive);
@@ -4030,18 +3970,34 @@ async function applyAbAttrsInternal(
queueShowAbility(pokemon, passive);
}
}
-
if (!quiet) {
- const message = attr.getTriggerMessage(pokemon, ability.name, args);
+ const message = attr.getTriggerMessage(pokemon, (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name, args);
if (message) {
- pokemon.scene.queueMessage(message);
+ if (isAsync) {
+ pokemon.scene.ui.showText(message, null, () => pokemon.scene.ui.showText(null, 0), null, true);
+ } else {
+ pokemon.scene.queueMessage(message);
+ }
}
}
+ };
+ const result = applyFunc(attr, passive);
+ if (result instanceof Promise) {
+ result.then(success => {
+ if (success) {
+ onApplySuccess();
+ }
+ applyNextAbAttr();
+ });
+ } else {
+ if (result) {
+ onApplySuccess();
+ }
+ applyNextAbAttr();
}
- }
-
- pokemon.scene.clearPhaseQueueSplice();
- }
+ };
+ applyNextAbAttr();
+ });
}
export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
@@ -4056,7 +4012,7 @@ export function applyPostBattleInitAbAttrs(attrType: Constructor,
pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
const simulated = args.length > 1 && args[1];
- return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, simulated);
+ return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, false, simulated);
}
export function applyPostDefendAbAttrs(attrType: Constructor,
@@ -4116,7 +4072,7 @@ export function applyPostSummonAbAttrs(attrType: Constructor,
export function applyPreSwitchOutAbAttrs(attrType: Constructor,
pokemon: Pokemon, ...args: any[]): Promise {
- return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, true);
+ return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, false, true);
}
export function applyPreStatChangeAbAttrs(attrType: Constructor,
@@ -4132,7 +4088,7 @@ export function applyPostStatChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
const simulated = args.length > 1 && args[1];
- return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, !simulated);
+ return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, false, !simulated);
}
export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor,
@@ -4142,7 +4098,7 @@ export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor,
pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise {
- return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, true);
+ return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, false, true);
}
export function applyPostTurnAbAttrs(attrType: Constructor,
@@ -4167,7 +4123,7 @@ export function applyPostTerrainChangeAbAttrs(attrType: Constructor,
pokemon: Pokemon, trapped: Utils.BooleanHolder, otherPokemon: Pokemon, ...args: any[]): Promise {
- return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args);
+ return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, otherPokemon, args), args, true);
}
export function applyPostBattleAbAttrs(attrType: Constructor,
@@ -4180,6 +4136,11 @@ export function applyPostFaintAbAttrs(attrType: Constructor,
return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args);
}
+function canApplyAttr(pokemon: Pokemon, attr: AbAttr): boolean {
+ const condition = attr.getCondition();
+ return !condition || condition(pokemon);
+}
+
function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive));
pokemon.scene.clearPhaseQueueSplice();
@@ -4735,10 +4696,10 @@ export function initAbilities() {
new Ability(Abilities.REFRIGERATE, 6)
.attr(MoveTypeChangeAttr, Type.ICE, 1.2, (user, target, move) => move.type === Type.NORMAL),
new Ability(Abilities.SWEET_VEIL, 6)
- .attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.SLEEP)
- .attr(UserFieldBattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
+ .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP)
+ .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY)
.ignorable()
- .partial(), // Mold Breaker ally should not be affected by Sweet Veil
+ .partial(),
new Ability(Abilities.STANCE_CHANGE, 6)
.attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr)
@@ -4848,15 +4809,20 @@ export function initAbilities() {
.attr(NoFusionAbilityAbAttr)
.bypassFaint(),
new Ability(Abilities.DISGUISE, 7)
+ .attr(PreDefendMoveDamageToOneAbAttr, (target, user, move) => target.formIndex === 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
+ .attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
+ .attr(PostBattleInitFormChangeAbAttr, () => 0)
+ .attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
+ .attr(PreDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
+ .attr(PostDefendDisguiseAbAttr)
.attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr)
.attr(UnsuppressableAbilityAbAttr)
.attr(NoTransformAbilityAbAttr)
.attr(NoFusionAbilityAbAttr)
- // Add BattlerTagType.DISGUISE if the pokemon is in its disguised form
- .conditionalAttr(pokemon => pokemon.formIndex === 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.DISGUISE, 0, false)
- .attr(DisguiseBlockDamageAbAttr, (target, user, move) => !!target.getTag(BattlerTagType.DISGUISE) && target.getAttackTypeEffectiveness(move.type, user) > 0, 0)
- .ignorable(),
+ .bypassFaint()
+ .ignorable()
+ .partial(),
new Ability(Abilities.BATTLE_BOND, 7)
.attr(PostVictoryFormChangeAbAttr, () => 2)
.attr(PostBattleInitFormChangeAbAttr, () => 1)
@@ -5028,8 +4994,7 @@ export function initAbilities() {
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, "'s Neutralizing Gas filled the area!"))
.partial(),
new Ability(Abilities.PASTEL_VEIL, 8)
- .attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.POISON)
- .attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
+ .attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
.ignorable(),
new Ability(Abilities.HUNGER_SWITCH, 8)
.attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1)
diff --git a/src/data/battle-stat.ts b/src/data/battle-stat.ts
index 4a8e15902b6b..7dccd4f8a7c3 100644
--- a/src/data/battle-stat.ts
+++ b/src/data/battle-stat.ts
@@ -1,4 +1,4 @@
-import i18next, {ParseKeys} from "i18next";
+import i18next from "i18next";
export enum BattleStat {
ATK,
@@ -8,8 +8,7 @@ export enum BattleStat {
SPD,
ACC,
EVA,
- RAND,
- HP
+ RAND
}
export function getBattleStatName(stat: BattleStat) {
@@ -28,15 +27,13 @@ export function getBattleStatName(stat: BattleStat) {
return i18next.t("pokemonInfo:Stat.ACC");
case BattleStat.EVA:
return i18next.t("pokemonInfo:Stat.EVA");
- case BattleStat.HP:
- return i18next.t("pokemonInfo:Stat.HPStat");
default:
return "???";
}
}
-export function getBattleStatLevelChangeDescription(pokemonNameWithAffix: string, stats: string, levels: integer, up: boolean,multiple: boolean = false) {
- let stringKey = (() => {
+export function getBattleStatLevelChangeDescription(pokemonNameWithAffix: string, stats: string, levels: integer, up: boolean) {
+ const stringKey = (() => {
if (up) {
switch (levels) {
case 1:
@@ -68,9 +65,5 @@ export function getBattleStatLevelChangeDescription(pokemonNameWithAffix: string
}
})();
- if (multiple) {
- stringKey += "Multiple";
- }
-
- return i18next.t(stringKey as ParseKeys, { pokemonNameWithAffix, stats });
+ return i18next.t(stringKey, { pokemonNameWithAffix, stats });
}
diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts
index 9c5c680da556..41b6f73ec282 100644
--- a/src/data/battler-tags.ts
+++ b/src/data/battler-tags.ts
@@ -7,7 +7,7 @@ import { StatusEffect } from "./status-effect";
import * as Utils from "../utils";
import { ChargeAttr, MoveFlags, allMoves } from "./move";
import { Type } from "./type";
-import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, ProtectStatAbAttr } from "./ability";
+import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability";
import { TerrainType } from "./terrain";
import { WeatherType } from "./weather";
import { BattleStat } from "./battle-stat";
@@ -1386,18 +1386,6 @@ export class IgnoreAccuracyTag extends BattlerTag {
}
}
-export class AlwaysGetHitTag extends BattlerTag {
- constructor(sourceMove: Moves) {
- super(BattlerTagType.ALWAYS_GET_HIT, BattlerTagLapseType.PRE_MOVE, 1, sourceMove);
- }
-}
-
-export class ReceiveDoubleDamageTag extends BattlerTag {
- constructor(sourceMove: Moves) {
- super(BattlerTagType.RECEIVE_DOUBLE_DAMAGE, BattlerTagLapseType.PRE_MOVE, 1, sourceMove);
- }
-}
-
export class SaltCuredTag extends BattlerTag {
private sourceIndex: integer;
@@ -1549,86 +1537,6 @@ export class IceFaceTag extends BattlerTag {
}
}
-/**
- * Provides the Disguise ability's effects.
- */
-export class DisguiseTag extends BattlerTag {
- constructor(sourceMove: Moves) {
- super(BattlerTagType.DISGUISE, BattlerTagLapseType.CUSTOM, 1, sourceMove);
- }
-
- /**
- * Determines if the Disguise tag can be added to the Pokémon.
- * @param {Pokemon} pokemon - The Pokémon to which the tag might be added.
- * @returns {boolean} - True if the tag can be added, false otherwise.
- */
- canAdd(pokemon: Pokemon): boolean {
- const isFormDisguised = pokemon.formIndex === 0;
-
- // Hard code Mimikyu for now, this is to prevent the game from crashing if fused pokemon has Disguise
- if (pokemon.species.speciesId === Species.MIMIKYU && isFormDisguised) {
- return true;
- }
- return false;
- }
-
- /**
- * Applies the Disguise tag to the Pokémon.
- * Triggers a form change to Disguised if the Pokémon is not in its Disguised form.
- * @param {Pokemon} pokemon - The Pokémon to which the tag is added.
- */
- onAdd(pokemon: Pokemon): void {
- super.onAdd(pokemon);
-
- if (pokemon.formIndex !== 0) {
- pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
- }
- }
-
- /**
- * Removes the Disguise tag from the Pokémon.
- * Triggers a form change to Busted when the tag is removed.
- * @param {Pokemon} pokemon - The Pokémon from which the tag is removed.
- */
- onRemove(pokemon: Pokemon): void {
- super.onRemove(pokemon);
-
- pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
- }
-}
-
-export class MysteryEncounterPostSummonTag extends BattlerTag {
- constructor(sourceMove: Moves) {
- super(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON, BattlerTagLapseType.CUSTOM, 1, sourceMove);
- }
-
- onAdd(pokemon: Pokemon): void {
- super.onAdd(pokemon);
- }
-
- lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
- const ret = super.lapse(pokemon, lapseType);
-
- if (lapseType === BattlerTagLapseType.CUSTOM) {
- // Give pokemon +1 stats for battle
- const cancelled = new Utils.BooleanHolder(false);
- applyAbAttrs(ProtectStatAbAttr, pokemon, cancelled);
- if (!cancelled.value) {
- const mysteryEncounterBattleEffects = pokemon.summonData.mysteryEncounterBattleEffects;
- if (mysteryEncounterBattleEffects) {
- mysteryEncounterBattleEffects(pokemon);
- }
- }
- }
-
- return ret;
- }
-
- onRemove(pokemon: Pokemon): void {
- super.onRemove(pokemon);
- }
-}
-
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
switch (tagType) {
case BattlerTagType.RECHARGING:
@@ -1726,10 +1634,6 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove);
case BattlerTagType.IGNORE_ACCURACY:
return new IgnoreAccuracyTag(sourceMove);
- case BattlerTagType.ALWAYS_GET_HIT:
- return new AlwaysGetHitTag(sourceMove);
- case BattlerTagType.RECEIVE_DOUBLE_DAMAGE:
- return new ReceiveDoubleDamageTag(sourceMove);
case BattlerTagType.BYPASS_SLEEP:
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
case BattlerTagType.IGNORE_FLYING:
@@ -1750,10 +1654,6 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new DestinyBondTag(sourceMove, sourceId);
case BattlerTagType.ICE_FACE:
return new IceFaceTag(sourceMove);
- case BattlerTagType.DISGUISE:
- return new DisguiseTag(sourceMove);
- case BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON:
- return new MysteryEncounterPostSummonTag(sourceMove);
case BattlerTagType.NONE:
default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
diff --git a/src/data/challenge.ts b/src/data/challenge.ts
index 32b98a04b969..75b200b24eee 100644
--- a/src/data/challenge.ts
+++ b/src/data/challenge.ts
@@ -422,21 +422,19 @@ export class SingleTypeChallenge extends Challenge {
const isValidStarter = args[1] as Utils.BooleanHolder;
const dexAttr = args[2] as DexAttrProps;
const amountOfPokemon = args[3] as number;
- const checkEvolutions = args[4] ?? true as boolean;
- const checkForms = args[5] ?? true as boolean;
const speciesForm = getPokemonSpeciesForm(species.speciesId, dexAttr.formIndex);
const types = [speciesForm.type1, speciesForm.type2];
if (amountOfPokemon > 0) {
const speciesToCheck = [species.speciesId];
while (speciesToCheck.length) {
const checking = speciesToCheck.pop();
- if (pokemonEvolutions.hasOwnProperty(checking) && checkEvolutions) {
+ if (pokemonEvolutions.hasOwnProperty(checking)) {
pokemonEvolutions[checking].forEach(e => {
speciesToCheck.push(e.speciesId);
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
});
}
- if (pokemonFormChanges.hasOwnProperty(checking) && checkForms) {
+ if (pokemonFormChanges.hasOwnProperty(checking)) {
pokemonFormChanges[checking].forEach(f1 => {
getPokemonSpecies(checking).forms.forEach(f2 => {
if (f1.formKey === f2.formKey) {
diff --git a/src/data/move.ts b/src/data/move.ts
index 5fda19a8b137..7fba094e6568 100644
--- a/src/data/move.ts
+++ b/src/data/move.ts
@@ -861,47 +861,6 @@ export class MoveEffectAttr extends MoveAttr {
}
}
-/**
- * Base class defining all Move Header attributes.
- * Move Header effects apply at the beginning of a turn before any moves are resolved.
- * They can be used to apply effects to the field (e.g. queueing a message) or to the user
- * (e.g. adding a battler tag).
- */
-export class MoveHeaderAttr extends MoveAttr {
- constructor() {
- super(true);
- }
-
- apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise {
- return true;
- }
-}
-
-/**
- * Header attribute to queue a message at the beginning of a turn.
- * @see {@link MoveHeaderAttr}
- */
-export class MessageHeaderAttr extends MoveHeaderAttr {
- private message: string | ((user: Pokemon, move: Move) => string);
-
- constructor(message: string | ((user: Pokemon, move: Move) => string)) {
- super();
- this.message = message;
- }
-
- apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
- const message = typeof this.message === "string"
- ? this.message as string
- : this.message(user, move);
-
- if (message) {
- user.scene.queueMessage(message);
- return true;
- }
- return false;
- }
-}
-
export class PreMoveMessageAttr extends MoveAttr {
private message: string | ((user: Pokemon, target: Pokemon, move: Move) => string);
@@ -4178,9 +4137,9 @@ export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
}
}
-export class AlwaysGetHitAttr extends AddBattlerTagAttr {
+export class AlwaysCritsAttr extends AddBattlerTagAttr {
constructor() {
- super(BattlerTagType.ALWAYS_GET_HIT, true, false, 0, 0, true);
+ super(BattlerTagType.ALWAYS_CRIT, true, false, 2);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
@@ -4188,19 +4147,7 @@ export class AlwaysGetHitAttr extends AddBattlerTagAttr {
return false;
}
- return true;
- }
-}
-
-export class ReceiveDoubleDamageAttr extends AddBattlerTagAttr {
- constructor() {
- super(BattlerTagType.RECEIVE_DOUBLE_DAMAGE, true, false, 0, 0, true);
- }
-
- apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
- if (!super.apply(user, target, move, args)) {
- return false;
- }
+ user.scene.queueMessage(getPokemonMessage(user, ` took aim\nat ${target.name}!`));
return true;
}
@@ -5693,10 +5640,6 @@ export const allMoves: Move[] = [
new SelfStatusMove(Moves.NONE, Type.NORMAL, MoveCategory.STATUS, -1, -1, 0, 1),
];
-export const selfStatLowerMoves: Moves[] = [
-
-];
-
export function initMoves() {
allMoves.push(
new AttackMove(Moves.POUND, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1),
@@ -6431,7 +6374,6 @@ export function initMoves() {
&& (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1)
.attr(BypassBurnDamageReductionAttr),
new AttackMove(Moves.FOCUS_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3)
- .attr(MessageHeaderAttr, (user, move) => getPokemonMessage(user, " is tightening its focus!"))
.punchingMove()
.ignoresVirtual()
.condition((user, target, move) => !user.turnData.attacksReceived.find(r => r.damage)),
@@ -8269,8 +8211,7 @@ export function initMoves() {
new AttackMove(Moves.ICE_SPINNER, Type.ICE, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9)
.attr(ClearTerrainAttr),
new AttackMove(Moves.GLAIVE_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 9)
- .attr(AlwaysGetHitAttr)
- .attr(ReceiveDoubleDamageAttr),
+ .partial(),
new StatusMove(Moves.REVIVAL_BLESSING, Type.NORMAL, -1, 1, -1, 0, 9)
.triageMove()
.attr(RevivalBlessingAttr)
@@ -8464,9 +8405,4 @@ export function initMoves() {
new AttackMove(Moves.MALIGNANT_CHAIN, Type.POISON, MoveCategory.SPECIAL, 100, 100, 5, 50, 0, 9)
.attr(StatusEffectAttr, StatusEffect.TOXIC)
);
- allMoves.map(m=>{
- if (m.getAttrs(StatChangeAttr).some(a=> a.selfTarget && a.levels < 0)) {
- selfStatLowerMoves.push(m.id);
- }
- });
}
diff --git a/src/data/mystery-encounter-flags.ts b/src/data/mystery-encounter-flags.ts
deleted file mode 100644
index 33ef84e2d1d3..000000000000
--- a/src/data/mystery-encounter-flags.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import {MysteryEncounterTier} from "#app/data/mystery-encounter";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import {BASE_MYSTERY_ENCOUNTER_WEIGHT} from "#app/data/mystery-encounters/mystery-encounters";
-import {isNullOrUndefined} from "../utils";
-
-export class MysteryEncounterFlags {
- encounteredEvents: [MysteryEncounterType, MysteryEncounterTier][] = [];
- encounterSpawnChance: number = BASE_MYSTERY_ENCOUNTER_WEIGHT;
- nextEncounterQueue: [MysteryEncounterType, integer][] = [];
-
- constructor(flags: MysteryEncounterFlags) {
- if (!isNullOrUndefined(flags)) {
- Object.assign(this, flags);
- }
- }
-}
diff --git a/src/data/mystery-encounter-option.ts b/src/data/mystery-encounter-option.ts
deleted file mode 100644
index 9f23a94e3f3c..000000000000
--- a/src/data/mystery-encounter-option.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import { PlayerPokemon } from "#app/field/pokemon";
-import * as Utils from "../utils";
-import BattleScene from "../battle-scene";
-import { EncounterPokemonRequirement, EncounterSceneRequirement } from "./mystery-encounter-requirements";
-import {OptionTextDisplay} from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export default interface MysteryEncounterOption {
- requirements?: EncounterSceneRequirement[];
- primaryPokemonRequirements?: EncounterPokemonRequirement[];
- secondaryPokemonRequirements ?: EncounterPokemonRequirement[];
- primaryPokemon?: PlayerPokemon;
- secondaryPokemon?: PlayerPokemon[];
- excludePrimaryFromSecondaryRequirements?: boolean;
-
- /**
- * Dialogue object containing all the dialogue, messages, tooltips, etc. for this option
- * Will be populated on MysteryEncounter initialization
- */
- dialogue?: OptionTextDisplay;
-
- // Executes before any following dialogue or business logic from option. Usually this will be for calculating dialogueTokens or performing scene/data updates
- onPreOptionPhase?: (scene: BattleScene) => Promise;
- // Business logic for option
- onOptionPhase?: (scene: BattleScene) => Promise;
- // Executes after the encounter is over. Usually this will be for calculating dialogueTokens or performing data updates
- onPostOptionPhase?: (scene: BattleScene) => Promise;
-}
-
-export default class MysteryEncounterOption implements MysteryEncounterOption {
- constructor(option: MysteryEncounterOption) {
- Object.assign(this, option);
- this.requirements = this.requirements ? this.requirements : [];
- }
-
- meetsRequirements?(scene: BattleScene) {
- return !this.requirements.some(requirement => !requirement.meetsRequirement(scene)) &&
- this.meetsPrimaryRequirementAndPrimaryPokemonSelected(scene) &&
- this.meetsSupportingRequirementAndSupportingPokemonSelected(scene);
- }
- meetsPrimaryRequirementAndPrimaryPokemonSelected?(scene: BattleScene) {
- if (!this.primaryPokemonRequirements) {
- return true;
- }
- let qualified:PlayerPokemon[] = scene.getParty();
- for (const req of this.primaryPokemonRequirements) {
- console.log(req);
- if (req.meetsRequirement(scene)) {
- if (req instanceof EncounterPokemonRequirement) {
- qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn));
- }
- } else {
- this.primaryPokemon = null;
- return false;
- }
- }
-
- if (qualified.length === 0) {
- return false;
- }
-
- if (this.excludePrimaryFromSecondaryRequirements && this.secondaryPokemon) {
- const truePrimaryPool = [];
- const overlap = [];
- for (const qp of qualified) {
- if (!this.secondaryPokemon.includes(qp)) {
- truePrimaryPool.push(qp);
- } else {
- overlap.push(qp);
- }
-
- }
- if (truePrimaryPool.length > 0) {
- // always choose from the non-overlapping pokemon first
- this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)];
- return true;
- } else {
- // if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the supporting pokemon pool
- if (overlap.length > 1 || (this.secondaryPokemon.length - overlap.length >= 1)) {
- // is this working?
- this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)];
- this.secondaryPokemon = this.secondaryPokemon.filter((supp)=> supp !== this.primaryPokemon);
- return true;
- }
- console.log("Mystery Encounter Edge Case: Requirement not met due to primay pokemon overlapping with support pokemon. There's no valid primary pokemon left.");
- return false;
- }
- } else {
- // this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
- this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)];
- return true;
- }
- }
-
- meetsSupportingRequirementAndSupportingPokemonSelected?(scene: BattleScene) {
- if (!this.secondaryPokemonRequirements) {
- this.secondaryPokemon = [];
- return true;
- }
-
- let qualified:PlayerPokemon[] = scene.getParty();
- for (const req of this.secondaryPokemonRequirements) {
- if (req.meetsRequirement(scene)) {
- if (req instanceof EncounterPokemonRequirement) {
- qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn));
-
- }
- } else {
- this.secondaryPokemon = [];
- return false;
- }
- }
- this.secondaryPokemon = qualified;
- return true;
- }
-}
-
-
-export class MysteryEncounterOptionBuilder implements Partial {
- requirements?: EncounterSceneRequirement[] = [];
- primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
- secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
- excludePrimaryFromSecondaryRequirements?: boolean;
- onPreOptionPhase?: (scene: BattleScene) => Promise;
- onOptionPhase?: (scene: BattleScene) => Promise;
- onPostOptionPhase?: (scene: BattleScene) => Promise;
-
- withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> {
- this.requirements.push(requirement);
- return Object.assign(this, { requirements: this.requirements });
- }
-
- withPreOptionPhase(onPreOptionPhase: (scene: BattleScene) => Promise): this & Required> {
- return Object.assign(this, { onPreOptionPhase: onPreOptionPhase });
- }
-
- withOptionPhase(onOptionPhase: (scene: BattleScene) => Promise): this & Required> {
- return Object.assign(this, { onOptionPhase: onOptionPhase });
- }
-
- withPostOptionPhase(onPostOptionPhase: (scene: BattleScene) => Promise): this & Required> {
- return Object.assign(this, { onPostOptionPhase: onPostOptionPhase });
- }
-
- build(this: MysteryEncounterOption) {
- return new MysteryEncounterOption(this);
- }
-
- withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> {
- this.primaryPokemonRequirements.push(requirement);
- return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements });
- }
-
- withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements?: boolean): this & Required> {
- this.secondaryPokemonRequirements.push(requirement);
- this.excludePrimaryFromSecondaryRequirements = excludePrimaryFromSecondaryRequirements;
- return Object.assign(this, { secondaryPokemonRequirements: this.secondaryPokemonRequirements });
- }
-}
diff --git a/src/data/mystery-encounter-requirements.ts b/src/data/mystery-encounter-requirements.ts
deleted file mode 100644
index d88ec530a74e..000000000000
--- a/src/data/mystery-encounter-requirements.ts
+++ /dev/null
@@ -1,914 +0,0 @@
-import { PlayerPokemon } from "#app/field/pokemon";
-import { ModifierType, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
-import BattleScene from "../battle-scene";
-import { isNullOrUndefined } from "../utils";
-import { Abilities } from "#enums/abilities";
-import { Moves } from "#enums/moves";
-import { Species } from "#enums/species";
-import { TimeOfDay } from "#enums/time-of-day";
-import { Nature } from "./nature";
-import { EvolutionItem, pokemonEvolutions } from "./pokemon-evolutions";
-import { FormChangeItem, SpeciesFormChangeItemTrigger, pokemonFormChanges } from "./pokemon-forms";
-import { SpeciesFormKey } from "./pokemon-species";
-import { StatusEffect } from "./status-effect";
-import { Type } from "./type";
-import { WeatherType } from "./weather";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-
-export interface EncounterRequirement {
- meetsRequirement(scene: BattleScene): boolean; // Boolean to see if a requirement is met
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string];
-}
-
-export abstract class EncounterSceneRequirement implements EncounterRequirement {
- meetsRequirement(scene: BattleScene): boolean {
- throw new Error("Method not implemented.");
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["", ""];
- }
-}
-
-export abstract class EncounterPokemonRequirement implements EncounterRequirement {
- minNumberOfPokemon: number;
- invertQuery: boolean;
-
- meetsRequirement(scene: BattleScene): boolean {
- throw new Error("Method not implemented.");
- }
-
- // Returns all party members that are compatible with this requirement. For non pokemon related requirements, the entire party is returned..
- queryParty(partyPokemon: PlayerPokemon[]) {
- return [];
- }
-
- // Doesn't require the "@ec" as prefix, just the string; populates the token with the attribute
- // ex. @ec{primarySpecies} if strPrefix is simply "primary"
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["", ""];
- }
-}
-
-export class PreviousEncounterRequirement extends EncounterSceneRequirement {
- previousEncounterRequirement: MysteryEncounterType;
-
- /**
- * Used for specifying an encounter that must be seen before this encounter can spawn
- * @param previousEncounterRequirement
- */
- constructor(previousEncounterRequirement) {
- super();
- this.previousEncounterRequirement = previousEncounterRequirement;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- return scene.mysteryEncounterFlags.encounteredEvents.some(e => e[0] === this.previousEncounterRequirement);
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["previousEncounter", scene.mysteryEncounterFlags.encounteredEvents.find(e => e[0] === this.previousEncounterRequirement)[0].toString()];
- }
-}
-
-export class WaveCountRequirement extends EncounterSceneRequirement {
- waveRange: [number, number];
-
- /**
- * Used for specifying a unique wave or wave range requirement
- * If minWaveIndex and maxWaveIndex are equivalent, will check for exact wave number
- * @param waveRange - [min, max]
- */
- constructor(waveRange: [number, number]) {
- super();
- this.waveRange = waveRange;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- if (!isNullOrUndefined(this?.waveRange) && this.waveRange?.[0] <= this.waveRange?.[1]) {
- const waveIndex = scene.currentBattle.waveIndex;
- if (waveIndex >= 0 && (this?.waveRange?.[0] >= 0 && this.waveRange?.[0] > waveIndex) || (this?.waveRange?.[1] >= 0 && this.waveRange?.[1] < waveIndex)) {
- return false;
- }
- }
- return true;
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["waveCount", scene.currentBattle.waveIndex.toString()];
- }
-}
-
-export class TimeOfDayRequirement extends EncounterSceneRequirement {
- requiredTimeOfDay?: TimeOfDay[];
-
- constructor(timeOfDay: TimeOfDay | TimeOfDay[]) {
- super();
- if (timeOfDay instanceof Array) {
- this.requiredTimeOfDay = timeOfDay;
- } else {
- this.requiredTimeOfDay = [];
- this.requiredTimeOfDay.push(timeOfDay);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const timeOfDay = scene.arena?.getTimeOfDay();
- if (!isNullOrUndefined(timeOfDay) && this?.requiredTimeOfDay?.length > 0 && !this.requiredTimeOfDay.includes(timeOfDay)) {
- return false;
- }
-
- return true;
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["timeOfDay", TimeOfDay[scene.arena.getTimeOfDay()].toLocaleLowerCase()];
- }
-}
-
-export class WeatherRequirement extends EncounterSceneRequirement {
- requiredWeather?: WeatherType[];
-
- constructor(weather: WeatherType | WeatherType[]) {
- super();
- if (weather instanceof Array) {
- this.requiredWeather = weather;
- } else {
- this.requiredWeather = [];
- this.requiredWeather.push(weather);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const currentWeather = scene.arena?.weather?.weatherType;
- if (!isNullOrUndefined(currentWeather) && this?.requiredWeather?.length > 0 && !this.requiredWeather.includes(currentWeather)) {
- return false;
- }
-
- return true;
- }
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["weather", WeatherType[scene.arena?.weather?.weatherType].replace("_", " ").toLocaleLowerCase()];
- }
-}
-
-export class PartySizeRequirement extends EncounterSceneRequirement {
- partySizeRange: [number, number];
-
- /**
- * Used for specifying a party size requirement
- * If min and max are equivalent, will check for exact size
- * @param partySizeRange - [min, max]
- */
- constructor(partySizeRange: [number, number]) {
- super();
- this.partySizeRange = partySizeRange;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- if (!isNullOrUndefined(this?.partySizeRange) && this.partySizeRange?.[0] <= this.partySizeRange?.[1]) {
- const partySize = scene.getParty().length;
- if (partySize >= 0 && (this?.partySizeRange?.[0] >= 0 && this.partySizeRange?.[0] > partySize) || (this?.partySizeRange?.[1] >= 0 && this.partySizeRange?.[1] < partySize)) {
- return false;
- }
- }
-
- return true;
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["partySize", scene.getParty().length.toString()];
- }
-}
-
-export class PersistentModifierRequirement extends EncounterSceneRequirement {
- requiredItems?: ModifierType[]; // TODO: not implemented
- constructor(item: ModifierType | ModifierType[]) {
- super();
- if (item instanceof Array) {
- this.requiredItems = item;
- } else {
- this.requiredItems = [];
- this.requiredItems.push(item);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const items = scene.modifiers;
-
- if (!isNullOrUndefined(items) && this?.requiredItems.length > 0 && this.requiredItems.filter((searchingMod) =>
- items.filter((itemInScene) => itemInScene.type.id === searchingMod.id).length > 0).length === 0) {
- return false;
- }
- return true;
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const requiredItemsInInventory = this.requiredItems.filter((a) => {
- scene.modifiers.filter((itemInScene) => itemInScene.type.id === a.id).length > 0;
- });
- if (requiredItemsInInventory.length > 0) {
- return ["requiredItem", requiredItemsInInventory[0].name];
- }
- return null;
- }
-}
-
-export class MoneyRequirement extends EncounterSceneRequirement {
- requiredMoney: number;
-
- constructor(requiredMoney: number) {
- super();
- this.requiredMoney = requiredMoney;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const money = scene.money;
- if (!isNullOrUndefined(money) && this?.requiredMoney > 0 && this.requiredMoney > money) {
- return false;
- }
- return true;
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["money", "₽" + scene.money.toString()];
- }
-}
-
-export class SpeciesRequirement extends EncounterPokemonRequirement {
- requiredSpecies: Species[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(species: Species | Species[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (species instanceof Array) {
- this.requiredSpecies = species;
- } else {
- this.requiredSpecies = [];
- this.requiredSpecies.push(species);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredSpecies?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredSpecies.filter((species) => pokemon.species.speciesId === species).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed speciess
- return partyPokemon.filter((pokemon) => this.requiredSpecies.filter((species) => pokemon.species.speciesId === species).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- if (this.requiredSpecies.includes(pokemon.species.speciesId)) {
- return ["species", Species[pokemon.species.speciesId]];
- }
- return null;
- }
-}
-
-
-export class NatureRequirement extends EncounterPokemonRequirement {
- requiredNature: Nature[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(nature: Nature | Nature[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (nature instanceof Array) {
- this.requiredNature = nature;
- } else {
- this.requiredNature = [];
- this.requiredNature.push(nature);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredNature?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredNature.filter((nature) => pokemon.nature === nature).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed natures
- return partyPokemon.filter((pokemon) => this.requiredNature.filter((nature) => pokemon.nature === nature).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- if (this.requiredNature.includes(pokemon.nature)) {
- return ["nature", Nature[pokemon.nature]];
- }
- return null;
- }
-}
-
-export class TypeRequirement extends EncounterPokemonRequirement {
- requiredType: Type[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(type: Type | Type[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (type instanceof Array) {
- this.requiredType = type;
- } else {
- this.requiredType = [];
- this.requiredType.push(type);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredType?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredType.filter((type) => pokemon.getTypes().includes(type)).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed types
- return partyPokemon.filter((pokemon) => this.requiredType.filter((type) => pokemon.getTypes().includes(type)).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const includedTypes = this.requiredType.filter((ty) => pokemon.getTypes().includes(ty));
- if (includedTypes.length > 0) {
- return ["type", Type[includedTypes[0]]];
- }
- return null;
- }
-}
-
-
-export class MoveRequirement extends EncounterPokemonRequirement {
- requiredMoves: Moves[] = [];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(moves: Moves | Moves[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (moves instanceof Array) {
- this.requiredMoves = moves;
- } else {
- this.requiredMoves = [];
- this.requiredMoves.push(moves);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredMoves?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move.moveId === reqMove).length > 0).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed moves
- return partyPokemon.filter((pokemon) => this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move.moveId === reqMove).length === 0).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const includedMoves = this.requiredMoves.filter((reqMove) => pokemon.moveset.filter((move) => move.moveId === reqMove).length > 0);
- if (includedMoves.length > 0) {
- return ["move", Moves[includedMoves[0]].replace("_", " ")];
- }
- return null;
- }
-
-}
-
-/**
- * Find out if Pokemon in the party are able to learn one of many specific moves by TM.
- * NOTE: Egg moves are not included as learnable.
- * NOTE: If the Pokemon already knows the move, this requirement will fail, since it's not technically learnable.
- */
-export class CompatibleMoveRequirement extends EncounterPokemonRequirement {
- requiredMoves: Moves[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(learnableMove: Moves | Moves[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (learnableMove instanceof Array) {
- this.requiredMoves = learnableMove;
- } else {
- this.requiredMoves = [];
- this.requiredMoves.push(learnableMove);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredMoves?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m.moveId === tm)).includes(learnableMove)).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed learnableMoves
- return partyPokemon.filter((pokemon) => this.requiredMoves.filter((learnableMove) => pokemon.compatibleTms.filter(tm => !pokemon.moveset.find(m => m.moveId === tm)).includes(learnableMove)).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const includedCompatMoves = this.requiredMoves.filter((reqMove) => pokemon.compatibleTms.filter((tm) => !pokemon.moveset.find(m => m.moveId === tm)).includes(reqMove));
- if (includedCompatMoves.length > 0) {
- return ["compatibleMove", Moves[includedCompatMoves[0]]];
- }
- return null;
- }
-
-}
-
-/*
-export class EvolutionTargetSpeciesRequirement extends EncounterPokemonRequirement {
- requiredEvolutionTargetSpecies: Species[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(evolutionTargetSpecies: Species | Species[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (evolutionTargetSpecies instanceof Array) {
- this.requiredEvolutionTargetSpecies = evolutionTargetSpecies;
- } else {
- this.requiredEvolutionTargetSpecies = [];
- this.requiredEvolutionTargetSpecies.push(evolutionTargetSpecies);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredEvolutionTargetSpecies?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredEvolutionTargetSpecies.filter((evolutionTargetSpecies) => pokemon.getEvolution()?.speciesId === evolutionTargetSpecies).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed evolutionTargetSpeciess
- return partyPokemon.filter((pokemon) => this.requiredEvolutionTargetSpecies.filter((evolutionTargetSpecies) => pokemon.getEvolution()?.speciesId === evolutionTargetSpecies).length === 0);
- }
- }
-
- getMatchingDialogueToken(str:string, pokemon: PlayerPokemon): [RegExp, string] {
- const evos = this.requiredEvolutionTargetSpecies.filter((evolutionTargetSpecies) => pokemon.getEvolution().speciesId === evolutionTargetSpecies);
- if (evos.length > 0) {
- return ["Evolution", Species[evos[0]]];
- }
- return null;
- }
-
-}*/
-
-export class AbilityRequirement extends EncounterPokemonRequirement {
- requiredAbilities: Abilities[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(abilities: Abilities | Abilities[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (abilities instanceof Array) {
- this.requiredAbilities = abilities;
- } else {
- this.requiredAbilities = [];
- this.requiredAbilities.push(abilities);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredAbilities?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredAbilities.filter((abilities) => pokemon.hasAbility(abilities)).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed abilitiess
- return partyPokemon.filter((pokemon) => this.requiredAbilities.filter((abilities) => pokemon.hasAbility(abilities)).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const reqAbilities = this.requiredAbilities.filter((a) => {
- pokemon.hasAbility(a);
- });
- if (reqAbilities.length > 0) {
- return ["ability", Abilities[reqAbilities[0]]];
- }
- return null;
- }
-}
-
-export class StatusEffectRequirement extends EncounterPokemonRequirement {
- requiredStatusEffect: StatusEffect[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(StatusEffect: StatusEffect | StatusEffect[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (StatusEffect instanceof Array) {
- this.requiredStatusEffect = StatusEffect;
- } else {
- this.requiredStatusEffect = [];
- this.requiredStatusEffect.push(StatusEffect);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredStatusEffect?.length < 0) {
- return false;
- }
- const x = this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- console.log(x);
- return x;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredStatusEffect.filter((StatusEffect) => pokemon.status?.effect === StatusEffect).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed StatusEffects
- return partyPokemon.filter((pokemon) => this.requiredStatusEffect.filter((StatusEffect) => pokemon.status?.effect === StatusEffect).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const reqStatus = this.requiredStatusEffect.filter((a) => {
- pokemon.status?.effect ===(a);
- });
- if (reqStatus.length > 0) {
- return ["status", StatusEffect[reqStatus[0]]];
- }
- return null;
- }
-
-}
-
-/**
- * Finds if there are pokemon that can form change with a given item.
- * Notice that we mean specific items, like Charizardite, not the Mega Bracelet.
- * If you want to trigger the event based on the form change enabler, use PersistentModifierRequirement.
- */
-export class CanFormChangeWithItemRequirement extends EncounterPokemonRequirement {
- requiredFormChangeItem: FormChangeItem[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(formChangeItem: FormChangeItem | FormChangeItem[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (formChangeItem instanceof Array) {
- this.requiredFormChangeItem = formChangeItem;
- } else {
- this.requiredFormChangeItem = [];
- this.requiredFormChangeItem.push(formChangeItem);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredFormChangeItem?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
- filterByForm(pokemon, formChangeItem) {
- if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)
- // Get all form changes for this species with an item trigger, including any compound triggers
- && pokemonFormChanges[pokemon.species.speciesId].filter(fc => fc.trigger.hasTriggerType(SpeciesFormChangeItemTrigger))
- // Returns true if any form changes match this item
- .map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
- .flat().flatMap(fc => fc.item).includes(formChangeItem)) {
- return true;
- } else {
- return false;
- }
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem)).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed formChangeItems
- return partyPokemon.filter((pokemon) => this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem)).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const requiredItems = this.requiredFormChangeItem.filter((formChangeItem) => this.filterByForm(pokemon, formChangeItem));
- if (requiredItems.length > 0) {
- return ["formChangeItem", FormChangeItem[requiredItems[0]]];
- }
- return null;
- }
-
-}
-
-export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
- requiredEvolutionItem: EvolutionItem[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(evolutionItems: EvolutionItem | EvolutionItem[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (evolutionItems instanceof Array) {
- this.requiredEvolutionItem = evolutionItems;
- } else {
- this.requiredEvolutionItem = [];
- this.requiredEvolutionItem.push(evolutionItems);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredEvolutionItem?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- filterByEvo(pokemon, evolutionItem) {
- if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === evolutionItem
- && (!e.condition || e.condition.predicate(pokemon))).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
- return true;
- } else if (pokemon.isFusion() && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === evolutionItem
- && (!e.condition || e.condition.predicate(pokemon))).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) {
- return true;
- }
- return false;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredEvolutionItem.filter((evolutionItem) => this.filterByEvo(pokemon, evolutionItem)).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed evolutionItemss
- return partyPokemon.filter((pokemon) => this.requiredEvolutionItem.filter((evolutionItems) => this.filterByEvo(pokemon, evolutionItems)).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const requiredItems = this.requiredEvolutionItem.filter((evoItem) => this.filterByEvo(pokemon, evoItem));
- if (requiredItems.length > 0) {
- return ["evolutionItem", EvolutionItem[requiredItems[0]]];
- }
- return null;
- }
-}
-
-export class HeldItemRequirement extends EncounterPokemonRequirement {
- requiredHeldItemModifier: PokemonHeldItemModifierType[];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(heldItem: PokemonHeldItemModifierType | PokemonHeldItemModifierType[], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- if (heldItem instanceof Array) {
- this.requiredHeldItemModifier = heldItem;
- } else {
- this.requiredHeldItemModifier = [];
- this.requiredHeldItemModifier.push(heldItem);
- }
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- const partyPokemon = scene.getParty();
- if (isNullOrUndefined(partyPokemon) || this?.requiredHeldItemModifier?.length < 0) {
- return false;
- }
- return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => this.requiredHeldItemModifier.filter((heldItem) => pokemon.getHeldItems().filter((it) => it.type.id === heldItem.id).length > 0).length > 0);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed heldItems
- return partyPokemon.filter((pokemon) => this.requiredHeldItemModifier.filter((heldItem) => pokemon.getHeldItems().filter((it) => it.type.id === heldItem.id).length === 0).length === 0);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- const requiredItems = this.requiredHeldItemModifier.filter((a) => {
- pokemon.getHeldItems().filter((it) => it.type.id === a.id ).length > 0;
- });
- if (requiredItems.length > 0) {
- return ["heldItem", requiredItems[0].name];
- }
- return null;
- }
-}
-
-export class LevelRequirement extends EncounterPokemonRequirement {
- requiredLevelRange?: [number, number];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(requiredLevelRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- this.requiredLevelRange = requiredLevelRange;
-
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- // Party Pokemon inside required level range
- if (!isNullOrUndefined(this?.requiredLevelRange) && this.requiredLevelRange?.[0] <= this.requiredLevelRange?.[1]) {
- const partyPokemon = scene.getParty();
- const pokemonInRange = this.queryParty(partyPokemon);
- if (pokemonInRange.length < this.minNumberOfPokemon) {
- return false;
- }
- }
- return true;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => pokemon.level >= this.requiredLevelRange[0] && pokemon.level <= this.requiredLevelRange[1]);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredLevelRanges
- return partyPokemon.filter((pokemon) => pokemon.level < this.requiredLevelRange[0] || pokemon.level > this.requiredLevelRange[1]);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["level", pokemon.level.toString()];
- }
-}
-
-export class FriendshipRequirement extends EncounterPokemonRequirement {
- requiredFriendshipRange?: [number, number];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(requiredFriendshipRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- this.requiredFriendshipRange = requiredFriendshipRange;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- // Party Pokemon inside required friendship range
- if (!isNullOrUndefined(this?.requiredFriendshipRange) && this.requiredFriendshipRange?.[0] <= this.requiredFriendshipRange?.[1]) {
- const partyPokemon = scene.getParty();
- const pokemonInRange = this.queryParty(partyPokemon);
- if (pokemonInRange.length < this.minNumberOfPokemon) {
- return false;
- }
- }
- return true;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => pokemon.friendship >= this.requiredFriendshipRange[0] && pokemon.friendship <= this.requiredFriendshipRange[1]);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredFriendshipRanges
- return partyPokemon.filter((pokemon) => pokemon.friendship < this.requiredFriendshipRange[0] || pokemon.friendship > this.requiredFriendshipRange[1]);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["friendship", pokemon.friendship.toString()];
- }
-}
-
-/**
- * .1 -> 10% hp
- * .5 -> 50% hp
- * 1 -> 100% hp
- */
-export class HealthRatioRequirement extends EncounterPokemonRequirement {
- requiredHealthRange?: [number, number];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(requiredHealthRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- this.requiredHealthRange = requiredHealthRange;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- // Party Pokemon inside required level range
- if (!isNullOrUndefined(this?.requiredHealthRange) && this.requiredHealthRange?.[0] <= this.requiredHealthRange?.[1]) {
- const partyPokemon = scene.getParty();
- const pokemonInRange = this.queryParty(partyPokemon);
- if (pokemonInRange.length < this.minNumberOfPokemon) {
- return false;
- }
- }
- return true;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => pokemon.getHpRatio() >= this.requiredHealthRange[0] && pokemon.getHpRatio() <= this.requiredHealthRange[1]);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredHealthRanges
- return partyPokemon.filter((pokemon) => pokemon.getHpRatio() < this.requiredHealthRange[0] || pokemon.getHpRatio() > this.requiredHealthRange[1]);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["healthRatio", Math.floor(pokemon.getHpRatio()*100).toString() + "%"];
- }
-}
-
-export class WeightRequirement extends EncounterPokemonRequirement {
- requiredWeightRange?: [number, number];
- minNumberOfPokemon:number;
- invertQuery:boolean;
-
- constructor(requiredWeightRange: [number, number], minNumberOfPokemon: number = 1, invertQuery: boolean = false) {
- super();
- this.minNumberOfPokemon = minNumberOfPokemon;
- this.invertQuery = invertQuery;
- this.requiredWeightRange = requiredWeightRange;
- }
-
- meetsRequirement(scene: BattleScene): boolean {
- // Party Pokemon inside required friendship range
- if (!isNullOrUndefined(this?.requiredWeightRange) && this.requiredWeightRange?.[0] <= this.requiredWeightRange?.[1]) {
- const partyPokemon = scene.getParty();
- const pokemonInRange = this.queryParty(partyPokemon);
- if (pokemonInRange.length < this.minNumberOfPokemon) {
- return false;
- }
- }
- return true;
- }
-
- queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
- if (!this.invertQuery) {
- return partyPokemon.filter((pokemon) => pokemon.getWeight() >= this.requiredWeightRange[0] && pokemon.getWeight() <= this.requiredWeightRange[1]);
- } else {
- // for an inverted query, we only want to get the pokemon that don't have ANY of the listed requiredWeightRanges
- return partyPokemon.filter((pokemon) => pokemon.getWeight() < this.requiredWeightRange[0] || pokemon.getWeight() > this.requiredWeightRange[1]);
- }
- }
-
- getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
- return ["weight", pokemon.getWeight().toString()];
- }
-}
diff --git a/src/data/mystery-encounter.ts b/src/data/mystery-encounter.ts
deleted file mode 100644
index 8325a26d29df..000000000000
--- a/src/data/mystery-encounter.ts
+++ /dev/null
@@ -1,489 +0,0 @@
-import BattleScene from "../battle-scene";
-import MysteryEncounterIntroVisuals, { MysteryEncounterSpriteConfig } from "../field/mystery-encounter-intro";
-import { MysteryEncounterType } from "#enums/mystery-encounter-type";
-import MysteryEncounterDialogue, {
- allMysteryEncounterDialogue
-} from "./mystery-encounters/dialogue/mystery-encounter-dialogue";
-import MysteryEncounterOption from "./mystery-encounter-option";
-import { EncounterPokemonRequirement, EncounterSceneRequirement } from "./mystery-encounter-requirements";
-import * as Utils from "../utils";
-import {EnemyPartyConfig} from "#app/data/mystery-encounters/mystery-encounter-utils";
-import { PlayerPokemon } from "#app/field/pokemon";
-import {isNullOrUndefined} from "../utils";
-
-export enum MysteryEncounterVariant {
- DEFAULT,
- TRAINER_BATTLE,
- WILD_BATTLE,
- BOSS_BATTLE,
- NO_BATTLE
-}
-
-export enum MysteryEncounterTier {
- COMMON,
- UNCOMMON,
- RARE,
- SUPER_RARE,
- ULTRA_RARE // Not currently used
-}
-
-export default interface MysteryEncounter {
- /**
- * Required params
- */
- encounterType: MysteryEncounterType;
- options: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]];
- spriteConfigs: MysteryEncounterSpriteConfig[];
- /**
- * Optional params
- */
- encounterTier?: MysteryEncounterTier;
- hideBattleIntroMessage?: boolean;
- hideIntroVisuals?: boolean;
- catchAllowed?: boolean;
- doEncounterRewards?: (scene: BattleScene) => boolean;
- onInit?: (scene: BattleScene) => boolean;
-
- /**
- * Requirements
- */
- requirements?: EncounterSceneRequirement[];
- primaryPokemonRequirements?: EncounterPokemonRequirement[];
- secondaryPokemonRequirements ?: EncounterPokemonRequirement[]; // A list of requirements that must ALL be met by a subset of pokemon to trigger the event
- excludePrimaryFromSupportRequirements?: boolean;
- // Primary Pokemon is a single pokemon randomly selected from a set of pokemon that meet ALL primary pokemon requirements
- primaryPokemon?: PlayerPokemon;
- // Support Pokemon are pokemon that meet ALL support pokemon requirements.
- // Note that an individual requirement may require multiple pokemon, but the resulting pokemon after all secondary requirements are met may be lower than expected
- // If the primary pokemon and supporting pokemon are the same and ExcludePrimaryFromSupportRequirements flag is true, primary pokemon may be promoted from secondary pool
- secondaryPokemon?: PlayerPokemon[];
-
- /**
- * Post-construct / Auto-populated params
- */
-
- /**
- * Dialogue object containing all the dialogue, messages, tooltips, etc. for an encounter
- */
- dialogue?: MysteryEncounterDialogue;
- /**
- * Data used for setting up/initializing enemy party in battles
- * Can store multiple configs so that one can be chosen based on option selected
- */
- enemyPartyConfigs?: EnemyPartyConfig[];
- /**
- * Object instance containing sprite data for an encounter when it is being spawned
- * Otherwise, will be undefined
- * You probably shouldn't do anything with this unless you have a very specific need
- */
- introVisuals?: MysteryEncounterIntroVisuals;
-
- /**
- * Flags
- */
-
- /**
- * Can be set for uses programatic dialogue during an encounter (storing the name of one of the party's pokemon, etc.)
- * Example use: see MYSTERIOUS_CHEST
- */
- dialogueTokens?: Map;
- /**
- * Should be set depending upon option selected as part of an encounter
- * For example, if there is no battle as part of the encounter/selected option, should be set to NO_BATTLE
- * Defaults to DEFAULT
- */
- encounterVariant?: MysteryEncounterVariant;
- /**
- * Flag for checking if it's the first time a shop is being shown for an encounter.
- * Defaults to true so that the first shop does not override the specified rewards.
- * Will be set to false after a shop is shown (so can't reroll same rarity items for free)
- */
- lockEncounterRewardTiers?: boolean;
- /**
- * Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases
- */
- selectedOption?: MysteryEncounterOption;
- /**
- * Can be set higher or lower based on the type of battle or exp gained for an option/encounter
- * Defaults to 1
- */
- expMultiplier?: number;
-
- /**
- * Generic property to set any custom data required for the encounter
- */
- misc?: any;
-}
-
-/**
- * MysteryEncounter class that defines the logic for a single encounter
- * These objects will be saved as part of session data any time the player is on a floor with an encounter
- * Unless you know what you're doing, you should use MysteryEncounterBuilder to create an instance for this class
- */
-export default class MysteryEncounter implements MysteryEncounter {
- constructor(encounter: MysteryEncounter) {
- if (!isNullOrUndefined(encounter)) {
- Object.assign(this, encounter);
- }
- this.encounterTier = this.encounterTier ? this.encounterTier : MysteryEncounterTier.COMMON;
- this.dialogue = allMysteryEncounterDialogue[this.encounterType];
- this.encounterVariant = MysteryEncounterVariant.DEFAULT;
- this.requirements = this.requirements ? this.requirements : [];
- this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false;
- this.hideIntroVisuals = !isNullOrUndefined(this.hideIntroVisuals) ? this.hideIntroVisuals : true;
-
- // Populate options with respective dialogue
- if (this.dialogue) {
- this.options.forEach((o, i) => o.dialogue = this.dialogue.encounterOptionsDialogue.options[i]);
- }
-
- // Reset any dirty flags or encounter data
- this.lockEncounterRewardTiers = true;
- this.dialogueTokens = new Map;
- this.enemyPartyConfigs = [];
- this.introVisuals = null;
- this.misc = null;
- this.expMultiplier = 1;
- }
-
- /**
- * Checks if the current scene state meets the requirements for the MysteryEncounter to spawn
- * This is used to filter the pool of encounters down to only the ones with all requirements met
- * @param scene
- * @returns
- */
- meetsRequirements?(scene: BattleScene) {
- const sceneReq = !this.requirements.some(requirement => !requirement.meetsRequirement(scene));
- const secReqs = this.meetsSecondaryRequirementAndSecondaryPokemonSelected(scene); // secondary is checked first to handle cases of primary overlapping with secondary
- const priReqs = this.meetsPrimaryRequirementAndPrimaryPokemonSelected(scene);
-
- // console.log("-------" + MysteryEncounterType[this.encounterType] + " Encounter Check -------");
- // console.log(this);
- // console.log( "sceneCheck: " + sceneReq);
- // console.log( "primaryCheck: " + priReqs);
- // console.log( "secondaryCheck: " + secReqs);
- // console.log(MysteryEncounterTier[this.encounterTier]);
-
- return sceneReq && secReqs && priReqs;
- }
-
- private meetsPrimaryRequirementAndPrimaryPokemonSelected?(scene: BattleScene) {
- if (this.primaryPokemonRequirements.length === 0) {
- const activeMon = scene.getParty().filter(p => p.isActive(true));
- if (activeMon.length > 0) {
- this.primaryPokemon = activeMon[0];
- } else {
- this.primaryPokemon = scene.getParty().filter(p => !p.isFainted())[0];
- }
- return true;
- }
- let qualified:PlayerPokemon[] = scene.getParty();
- for (const req of this.primaryPokemonRequirements) {
- console.log(req);
- if (req.meetsRequirement(scene)) {
- if (req instanceof EncounterPokemonRequirement) {
- qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn));
- }
- } else {
- this.primaryPokemon = null;
- return false;
- }
- }
-
- if (qualified.length === 0) {
- return false;
- }
-
- if (this.excludePrimaryFromSupportRequirements && this.secondaryPokemon) {
- const truePrimaryPool = [];
- const overlap = [];
- for (const qp of qualified) {
- if (!this.secondaryPokemon.includes(qp)) {
- truePrimaryPool.push(qp);
- } else {
- overlap.push(qp);
- }
-
- }
- if (truePrimaryPool.length > 0) {
- // always choose from the non-overlapping pokemon first
- this.primaryPokemon = truePrimaryPool[Utils.randSeedInt(truePrimaryPool.length, 0)];
- return true;
- } else {
- // if there are multiple overlapping pokemon, we're okay - just choose one and take it out of the primary pokemon pool
- if (overlap.length > 1 || (this.secondaryPokemon.length - overlap.length >= 1)) {
- // is this working?
- this.primaryPokemon = overlap[Utils.randSeedInt(overlap.length, 0)];
- this.secondaryPokemon = this.secondaryPokemon.filter((supp)=> supp !== this.primaryPokemon);
- return true;
- }
- console.log("Mystery Encounter Edge Case: Requirement not met due to primary pokemon overlapping with secondary pokemon. There's no valid primary pokemon left.");
- return false;
- }
- } else {
- // this means we CAN have the same pokemon be a primary and secondary pokemon, so just choose any qualifying one randomly.
- this.primaryPokemon = qualified[Utils.randSeedInt(qualified.length, 0)];
- return true;
- }
- }
-
- private meetsSecondaryRequirementAndSecondaryPokemonSelected?(scene: BattleScene) {
- if (!this.secondaryPokemonRequirements) {
- this.secondaryPokemon = [];
- return true;
- }
-
- let qualified:PlayerPokemon[] = scene.getParty();
- for (const req of this.secondaryPokemonRequirements) {
- if (req.meetsRequirement(scene)) {
- if (req instanceof EncounterPokemonRequirement) {
- qualified = qualified.filter(pkmn => req.queryParty(scene.getParty()).includes(pkmn));
-
- }
- } else {
- this.secondaryPokemon = [];
- return false;
- }
- }
- this.secondaryPokemon = qualified;
- return true;
- }
-
- /**
- * Initializes encounter intro sprites based on the sprite configs defined in spriteConfigs
- * @param scene
- */
- initIntroVisuals?(scene: BattleScene) {
- this.introVisuals = new MysteryEncounterIntroVisuals(scene, this);
- }
-
- /**
- * Auto-pushes dialogue tokens from the encounter (and option) requirements.
- * Will use the first support pokemon in list
- * For multiple support pokemon in the dialogue token, it will have to be overridden.
- */
- populateDialogueTokensFromRequirements?(scene: BattleScene) {
- if (this.primaryPokemon?.length > 0) {
- this.setDialogueToken("primaryName", this.primaryPokemon.name);
- for (const req of this.primaryPokemonRequirements) {
- if (!req.invertQuery) {
- const value = req.getDialogueToken(scene, this.primaryPokemon);
- this.setDialogueToken("primary" + this.capitalizeFirstLetter(value[0]), value[1]);
- }
- }
- }
- if (this.secondaryPokemonRequirements?.length > 0 && this.secondaryPokemon?.length > 0) {
- this.setDialogueToken("secondaryName", this.secondaryPokemon[0].name);
- for (const req of this.secondaryPokemonRequirements) {
- if (!req.invertQuery) {
- const value = req.getDialogueToken(scene, this.secondaryPokemon[0]);
- this.setDialogueToken("secondary" + this.capitalizeFirstLetter(value[0]), value[1]);
- }
- }
- }
- for (let i = 0; i < this.options.length; i++) {
- const opt = this.options[i];
- const j = i + 1;
- if (opt.primaryPokemonRequirements?.length > 0 && opt.primaryPokemon?.length > 0) {
- this.setDialogueToken("option" + j + "PrimaryName", opt.primaryPokemon.name);
- for (const req of opt.primaryPokemonRequirements) {
- if (!req.invertQuery) {
- const value = req.getDialogueToken(scene, opt.primaryPokemon);
- this.setDialogueToken("option" + j + "Primary", value[1]);
- }
- }
- }
- if (opt.secondaryPokemonRequirements?.length > 0 && opt.secondaryPokemon?.length > 0) {
- this.setDialogueToken("option" + j + "SecondaryName", opt.secondaryPokemon[0].name);
- for (const req of opt.secondaryPokemonRequirements) {
- if (!req.invertQuery) {
- const value = req.getDialogueToken(scene, opt.secondaryPokemon[0]);
- this.setDialogueToken("option" + j + "Secondary", value[1]);
- }
- }
- }
- }
- }
-
- setDialogueToken?(key: string, value: string) {
- this.dialogueTokens.set(key, [new RegExp("@ec\{" + key + "\\}", "gi"), value]);
- }
-
- private capitalizeFirstLetter?(str: string) {
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
-}
-
-export class MysteryEncounterBuilder implements Partial {
- encounterType?: MysteryEncounterType;
- options?: [MysteryEncounterOption, MysteryEncounterOption, ...MysteryEncounterOption[]] = [null, null];
- spriteConfigs?: MysteryEncounterSpriteConfig[];
-
- dialogue?: MysteryEncounterDialogue;
- encounterTier?: MysteryEncounterTier;
- requirements?: EncounterSceneRequirement[] = [];
- primaryPokemonRequirements?: EncounterPokemonRequirement[] = [];
- secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
- excludePrimaryFromSupportRequirements?: boolean;
- dialogueTokens?: Map;
- doEncounterRewards?: (scene: BattleScene) => boolean;
- onInit?: (scene: BattleScene) => boolean;
- hideBattleIntroMessage?: boolean;
- hideIntroVisuals?: boolean;
- enemyPartyConfigs?: EnemyPartyConfig[] = [];
-
- /**
- * REQUIRED
- */
-
- /**
- * Defines the type of encounter which is used as an identifier, should be tied to a unique MysteryEncounterType
- * @param encounterType
- * @returns this
- */
- withEncounterType(encounterType: MysteryEncounterType): this & Pick {
- return Object.assign(this, { encounterType: encounterType });
- }
-
- /**
- * Defines an option for the encounter
- * There should be at least 2 options defined and no more than 4
- * @param option - MysteryEncounterOption to add, can use MysteryEncounterOptionBuilder to create instance
- * @returns
- */
- withOption(option: MysteryEncounterOption): this & Pick {
- if (this.options[0] === null) {
- return Object.assign(this, { options: [ option, this.options[0] ] });
- } else if (this.options[1] === null) {
- return Object.assign(this, { options: [this.options[0], option ] });
- } else {
- this.options.push(option);
- return Object.assign(this, { options: this.options });
- }
- }
-
- /**
- * Defines the sprites that will be shown on the enemy field when the encounter spawns
- * Can be one or more sprites, recommended not to exceed 4
- * @param spriteConfigs
- * @returns
- */
- withIntroSpriteConfigs(spriteConfigs: MysteryEncounterSpriteConfig[]): this & Pick {
- return Object.assign(this, { spriteConfigs: spriteConfigs });
- }
-
- /**
- * OPTIONAL
- */
-
- /**
- * Sets the rarity tier for an encounter
- * If not specified, defaults to COMMON
- * Tiers are:
- * COMMON 32/64 odds
- * UNCOMMON 16/64 odds
- * RARE 10/64 odds
- * SUPER_RARE 6/64 odds
- * ULTRA_RARE Not currently used
- * @param encounterTier
- * @returns
- */
- withEncounterTier(encounterTier: MysteryEncounterTier): this & Required> {
- return Object.assign(this, { encounterTier: encounterTier });
- }
-
- /**
- * Specifies a requirement for an encounter
- * For example, passing requirement as "new WaveCountRequirement([2, 180])" would create a requirement that the encounter can only be spawned between waves 2 and 180
- * Existing Requirement objects are defined in mystery-encounter-requirements.ts, and more can always be created to meet a requirement need
- * @param requirement
- * @returns
- */
- withSceneRequirement(requirement: EncounterSceneRequirement): this & Required> {
- if (requirement instanceof EncounterPokemonRequirement) {
- Error("Incorrectly added pokemon requirement as scene requirement.");
- }
- this.requirements.push(requirement);
- return Object.assign(this, { requirements: this.requirements });
- }
-
- withPrimaryPokemonRequirement(requirement: EncounterPokemonRequirement): this & Required> {
- this.primaryPokemonRequirements.push(requirement);
- return Object.assign(this, { primaryPokemonRequirements: this.primaryPokemonRequirements });
- }
-
- // TODO: Maybe add an optional parameter for excluding primary pokemon from the support cast?
- // ex. if your only grass type pokemon, a snivy, is chosen as primary, if the support pokemon requires a grass type, the event won't trigger because
- // it's already been
- withSecondaryPokemonRequirement(requirement: EncounterPokemonRequirement, excludePrimaryFromSecondaryRequirements:boolean = false): this & Required> {
- this.secondaryPokemonRequirements.push(requirement);
- this.excludePrimaryFromSupportRequirements = excludePrimaryFromSecondaryRequirements;
- return Object.assign(this, { excludePrimaryFromSecondaryRequirements: this.excludePrimaryFromSupportRequirements, secondaryPokemonRequirements: this.secondaryPokemonRequirements });
- }
-
- /**
- * Can set custom encounter rewards via this callback function
- * If rewards are always deterministic for an encounter, this is a good way to set them
- *
- * NOTE: If rewards are dependent on options selected, runtime data, etc.,
- * It may be better to programmatically set doEncounterRewards elsewhere.
- * For instance, doEncounterRewards could instead be set inside the onOptionPhase() callback function for a MysteryEncounterOption
- * Check other existing mystery encounters for examples on how to use this
- * @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter
- * @returns
- */
- withRewards(doEncounterRewards: (scene: BattleScene) => boolean): this & Required> {
- return Object.assign(this, { doEncounterRewards: doEncounterRewards });
- }
-
- /**
- * Can be used to perform init logic before intro visuals are shown and before the MysteryEncounterPhase begins
- * Useful for performing things like procedural generation of intro sprites, etc.
- *
- * @param onInit - synchronous callback function to perform as soon as the encounter is selected for the next phase
- * @returns
- */
- withOnInit(onInit: (scene: BattleScene) => boolean): this & Required> {
- return Object.assign(this, { onInit: onInit });
- }
-
- /**
- * Defines any enemies to use for a battle from the mystery encounter
- * @param enemyPartyConfig
- * @returns
- */
- withEnemyPartyConfig(enemyPartyConfig: EnemyPartyConfig): this & Required> {
- this.enemyPartyConfigs.push(enemyPartyConfig);
- return Object.assign(this, { enemyPartyConfigs: this.enemyPartyConfigs });
- }
-
- /**
- * Can set whether catching is allowed or not on the encounter
- * This flag can also be programmatically set inside option event functions or elsewhere
- * @param catchAllowed - if true, allows enemy pokemon to be caught during the encounter
- * @returns
- */
- withCatchAllowed(catchAllowed: boolean): this & Required> {
- return Object.assign(this, { catchAllowed: catchAllowed });
- }
-
- /**
- * @param hideBattleIntroMessage - if true, will not show the trainerAppeared/wildAppeared/bossAppeared message for an encounter
- * @returns
- */
- withHideWildIntroMessage(hideBattleIntroMessage: boolean): this & Required> {
- return Object.assign(this, { hideBattleIntroMessage: hideBattleIntroMessage });
- }
-
- /**
- * @param hideIntroVisuals - if false, will not hide the intro visuals that are displayed at the beginning of encounter
- * @returns
- */
- withHideIntroVisuals(hideIntroVisuals: boolean): this & Required> {
- return Object.assign(this, { hideIntroVisuals: hideIntroVisuals });
- }
-
- build(this: MysteryEncounter) {
- return new MysteryEncounter(this);
- }
-}
diff --git a/src/data/mystery-encounters/dark-deal.ts b/src/data/mystery-encounters/dark-deal.ts
deleted file mode 100644
index 170e9ac01b73..000000000000
--- a/src/data/mystery-encounters/dark-deal.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-import BattleScene from "../../battle-scene";
-import {AddPokeballModifierType} from "../../modifier/modifier-type";
-import {
- EnemyPartyConfig, EnemyPokemonConfig,
- getRandomPlayerPokemon,
- getRandomSpeciesByStarterTier,
- initBattleWithEnemyConfig,
- leaveEncounterWithoutBattle
-} from "./mystery-encounter-utils";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import {ModifierRewardPhase} from "#app/phases";
-import {getPokemonSpecies} from "../pokemon-species";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import {PokeballType} from "../pokeball";
-import {PartySizeRequirement, WaveCountRequirement} from "../mystery-encounter-requirements";
-import {MysteryEncounterOptionBuilder} from "../mystery-encounter-option";
-import {Type} from "#app/data/type";
-import {Species} from "#enums/species";
-import {isNullOrUndefined, randSeedInt} from "#app/utils";
-
-// Exclude Ultra Beasts, Paradox, Necrozma, Eternatus, and egg-locked mythicals
-const excludedBosses = [
- Species.NECROZMA,
- Species.ETERNATUS,
- Species.NIHILEGO,
- Species.BUZZWOLE,
- Species.PHEROMOSA,
- Species.XURKITREE,
- Species.CELESTEELA,
- Species.KARTANA,
- Species.GUZZLORD,
- Species.POIPOLE,
- Species.NAGANADEL,
- Species.STAKATAKA,
- Species.BLACEPHALON,
- Species.GREAT_TUSK,
- Species.SCREAM_TAIL,
- Species.BRUTE_BONNET,
- Species.FLUTTER_MANE,
- Species.SLITHER_WING,
- Species.SANDY_SHOCKS,
- Species.ROARING_MOON,
- Species.KORAIDON,
- Species.WALKING_WAKE,
- Species.GOUGING_FIRE,
- Species.RAGING_BOLT,
- Species.IRON_TREADS,
- Species.IRON_BUNDLE,
- Species.IRON_HANDS,
- Species.IRON_JUGULIS,
- Species.IRON_MOTH,
- Species.IRON_THORNS,
- Species.IRON_VALIANT,
- Species.MIRAIDON,
- Species.IRON_LEAVES,
- Species.IRON_BOULDER,
- Species.IRON_CROWN,
- Species.MEW,
- Species.CELEBI,
- Species.DEOXYS,
- Species.JIRACHI,
- Species.PHIONE,
- Species.MANAPHY,
- Species.ARCEUS,
- Species.VICTINI,
- Species.MELTAN,
- Species.PECHARUNT
-];
-
-export const DarkDealEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.DARK_DEAL)
- .withEncounterTier(MysteryEncounterTier.ULTRA_RARE)
- .withIntroSpriteConfigs([
- {
- spriteKey: "mad_scientist_m",
- fileRoot: "mystery-encounters",
- hasShadow: true
- },
- {
- spriteKey: "dark_deal_porygon",
- fileRoot: "mystery-encounters",
- hasShadow: true,
- repeat: true
- }
- ])
- .withSceneRequirement(new WaveCountRequirement([30, 180])) // waves 30 to 180
- .withSceneRequirement(new PartySizeRequirement([2, 6])) // Must have at least 2 pokemon in party
- .withCatchAllowed(true)
- .withOption(new MysteryEncounterOptionBuilder()
- .withPreOptionPhase(async (scene: BattleScene) => {
- // Removes random pokemon (including fainted) from party and adds name to dialogue data tokens
- // Will never return last battle able mon and instead pick fainted/unable to battle
- const removedPokemon = getRandomPlayerPokemon(scene, false, true);
- scene.removePokemonFromPlayerParty(removedPokemon);
-
- scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", removedPokemon.name);
-
- // Store removed pokemon types
- scene.currentBattle.mysteryEncounter.misc = [removedPokemon.species.type1];
- if (removedPokemon.species.type2) {
- scene.currentBattle.mysteryEncounter.misc.push(removedPokemon.species.type2);
- }
- })
- .withOptionPhase(async (scene: BattleScene) => {
- // Give the player 5 Rogue Balls
- scene.unshiftPhase(new ModifierRewardPhase(scene, () => new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5)));
-
- // Start encounter with random legendary (7-10 starter strength) that has level additive
- const bossTypes = scene.currentBattle.mysteryEncounter.misc as Type[];
- // Starter egg tier, 35/50/10/5 %odds for tiers 6/7/8/9+
- const roll = randSeedInt(100);
- const starterTier: number | [number, number] = roll > 65 ? 6 : roll > 15 ? 7 : roll > 5 ? 8 : [9, 10];
- const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes));
- const pokemonConfig: EnemyPokemonConfig = {
- species: bossSpecies,
- isBoss: true
- };
- if (!isNullOrUndefined(bossSpecies.forms) && bossSpecies.forms.length > 0) {
- pokemonConfig.formIndex = 0;
- }
- const config: EnemyPartyConfig = {
- levelAdditiveMultiplier: 0.75,
- pokemonConfigs: [pokemonConfig]
- };
- return initBattleWithEnemyConfig(scene, config);
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Leave encounter with no rewards or exp
- leaveEncounterWithoutBattle(scene, true);
- return true;
- })
- .build())
- .build();
diff --git a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts b/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts
deleted file mode 100644
index 2fe86b046405..000000000000
--- a/src/data/mystery-encounters/dialogue/dark-deal-dialogue.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const DarkDealDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:dark_deal_intro_message"
- },
- {
- speaker: "mysteryEncounter:dark_deal_speaker",
- text: "mysteryEncounter:dark_deal_intro_dialogue"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:dark_deal_title",
- description: "mysteryEncounter:dark_deal_description",
- query: "mysteryEncounter:dark_deal_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:dark_deal_option_1_label",
- buttonTooltip: "mysteryEncounter:dark_deal_option_1_tooltip",
- selected: [
- {
- speaker: "mysteryEncounter:dark_deal_speaker",
- text: "mysteryEncounter:dark_deal_option_1_selected"
- },
- {
- text: "mysteryEncounter:dark_deal_option_1_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:dark_deal_option_2_label",
- buttonTooltip: "mysteryEncounter:dark_deal_option_2_tooltip",
- selected: [
- {
- speaker: "mysteryEncounter:dark_deal_speaker",
- text: "mysteryEncounter:dark_deal_option_2_selected"
- }
- ]
- }
- ]
- },
- outro: [
- {
- text: "mysteryEncounter:dark_deal_outro"
- }
- ]
-};
diff --git a/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts b/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts
deleted file mode 100644
index 300f6c45992f..000000000000
--- a/src/data/mystery-encounters/dialogue/fight-or-flight-dialogue.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const FightOrFlightDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:fight_or_flight_intro_message"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:fight_or_flight_title",
- description: "mysteryEncounter:fight_or_flight_description",
- query: "mysteryEncounter:fight_or_flight_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:fight_or_flight_option_1_label",
- buttonTooltip: "mysteryEncounter:fight_or_flight_option_1_tooltip",
- selected: [
- {
- text: "mysteryEncounter:fight_or_flight_option_1_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:fight_or_flight_option_2_label",
- buttonTooltip: "mysteryEncounter:fight_or_flight_option_2_tooltip"
- },
- {
- buttonLabel: "mysteryEncounter:fight_or_flight_option_3_label",
- buttonTooltip: "mysteryEncounter:fight_or_flight_option_3_tooltip",
- selected: [
- {
- text: "mysteryEncounter:fight_or_flight_option_3_selected"
- }
- ]
- }
- ]
- }
-};
diff --git a/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts b/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts
deleted file mode 100644
index a5699736a36e..000000000000
--- a/src/data/mystery-encounters/dialogue/mysterious-challengers-dialogue.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const MysteriousChallengersDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:mysterious_challengers_intro_message"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:mysterious_challengers_title",
- description: "mysteryEncounter:mysterious_challengers_description",
- query: "mysteryEncounter:mysterious_challengers_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:mysterious_challengers_option_1_label",
- buttonTooltip: "mysteryEncounter:mysterious_challengers_option_1_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_challengers_option_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:mysterious_challengers_option_2_label",
- buttonTooltip: "mysteryEncounter:mysterious_challengers_option_2_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_challengers_option_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:mysterious_challengers_option_3_label",
- buttonTooltip: "mysteryEncounter:mysterious_challengers_option_3_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_challengers_option_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:mysterious_challengers_option_4_label",
- buttonTooltip: "mysteryEncounter:mysterious_challengers_option_4_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_challengers_option_4_selected_message"
- }
- ]
- }
- ]
- },
- outro: [
- {
- text: "mysteryEncounter:mysterious_challengers_outro_win"
- }
- ]
-};
diff --git a/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts b/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts
deleted file mode 100644
index cc14670d5b47..000000000000
--- a/src/data/mystery-encounters/dialogue/mysterious-chest-dialogue.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const MysteriousChestDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:mysterious_chest_intro_message"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:mysterious_chest_title",
- description: "mysteryEncounter:mysterious_chest_description",
- query: "mysteryEncounter:mysterious_chest_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:mysterious_chest_option_1_label",
- buttonTooltip: "mysteryEncounter:mysterious_chest_option_1_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_chest_option_1_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:mysterious_chest_option_2_label",
- buttonTooltip: "mysteryEncounter:mysterious_chest_option_2_tooltip",
- selected: [
- {
- text: "mysteryEncounter:mysterious_chest_option_2_selected_message"
- }
- ]
- }
- ]
- }
-};
diff --git a/src/data/mystery-encounters/dialogue/mystery-encounter-dialogue.ts b/src/data/mystery-encounters/dialogue/mystery-encounter-dialogue.ts
deleted file mode 100644
index e390b0e706a1..000000000000
--- a/src/data/mystery-encounters/dialogue/mystery-encounter-dialogue.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import {MysteriousChallengersDialogue} from "#app/data/mystery-encounters/dialogue/mysterious-challengers-dialogue";
-import {MysteriousChestDialogue} from "#app/data/mystery-encounters/dialogue/mysterious-chest-dialogue";
-import {DarkDealDialogue} from "#app/data/mystery-encounters/dialogue/dark-deal-dialogue";
-import {FightOrFlightDialogue} from "#app/data/mystery-encounters/dialogue/fight-or-flight-dialogue";
-import {TrainingSessionDialogue} from "#app/data/mystery-encounters/dialogue/training-session-dialogue";
-import { SleepingSnorlaxDialogue } from "./sleeping-snorlax-dialogue";
-
-export class TextDisplay {
- speaker?: TemplateStringsArray | `mysteryEncounter:${string}`;
- text: TemplateStringsArray | `mysteryEncounter:${string}`;
-}
-
-export class OptionTextDisplay {
- buttonLabel: TemplateStringsArray | `mysteryEncounter:${string}`;
- buttonTooltip?: TemplateStringsArray | `mysteryEncounter:${string}`;
- disabledTooltip?: TemplateStringsArray | `mysteryEncounter:${string}`;
- secondOptionPrompt?: TemplateStringsArray | `mysteryEncounter:${string}`;
- selected?: TextDisplay[];
-}
-
-export class EncounterOptionsDialogue {
- title: TemplateStringsArray | `mysteryEncounter:${string}`;
- description: TemplateStringsArray | `mysteryEncounter:${string}`;
- query?: TemplateStringsArray | `mysteryEncounter:${string}`;
- options: [OptionTextDisplay, OptionTextDisplay, ...OptionTextDisplay[]]; // Options array with minimum 2 options
-}
-
-export default class MysteryEncounterDialogue {
- intro?: TextDisplay[];
- encounterOptionsDialogue: EncounterOptionsDialogue;
- outro?: TextDisplay[];
-}
-
-export interface EncounterTypeDialogue {
- [key: integer]: MysteryEncounterDialogue
-}
-
-
-/**
- * Example MysteryEncounterDialogue object:
- *
- {
- intro: [
- {
- text: "this is a rendered as a message window (no title display)"
- },
- {
- speaker: "John"
- text: "this is a rendered as a dialogue window (title "John" is displayed above text)"
- }
- ],
- encounterOptionsDialogue: {
- title: "This is the title displayed at top of encounter description box",
- description: "This is the description in the middle of encounter description box",
- query: "This is an optional question displayed at the bottom of the description box (keep it short)",
- options: [
- {
- buttonLabel: "Option #1 button label (keep these short)",
- selected: [ // Optional dialogue windows displayed when specific option is selected and before functional logic for the option is executed
- {
- text: "You chose option #1 message"
- },
- {
- speaker: "John"
- text: "So, you've chosen option #1! It's time to d-d-d-duel!"
- }
- ]
- },
- {
- buttonLabel: "Option #2"
- }
- ],
- },
- outro: [
- {
- text: "This message will be displayed at the very end of the encounter (i.e. post battle, post reward, etc.)"
- }
- ],
- }
- *
- */
-
-
-export const allMysteryEncounterDialogue: EncounterTypeDialogue = {};
-
-export function initMysteryEncounterDialogue() {
- allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHALLENGERS] = MysteriousChallengersDialogue;
- allMysteryEncounterDialogue[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestDialogue;
- allMysteryEncounterDialogue[MysteryEncounterType.DARK_DEAL] = DarkDealDialogue;
- allMysteryEncounterDialogue[MysteryEncounterType.FIGHT_OR_FLIGHT] = FightOrFlightDialogue;
- allMysteryEncounterDialogue[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionDialogue;
- allMysteryEncounterDialogue[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxDialogue;
-}
diff --git a/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts b/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts
deleted file mode 100644
index 0d9381d82780..000000000000
--- a/src/data/mystery-encounters/dialogue/sleeping-snorlax-dialogue.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const SleepingSnorlaxDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:sleeping_snorlax_intro_message"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:sleeping_snorlax_title",
- description: "mysteryEncounter:sleeping_snorlax_description",
- query: "mysteryEncounter:sleeping_snorlax_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:sleeping_snorlax_option_1_label",
- buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_1_tooltip",
- selected: [
- {
- text: "mysteryEncounter:sleeping_snorlax_option_1_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:sleeping_snorlax_option_2_label",
- buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_2_tooltip",
- selected: [
- {
- text: "mysteryEncounter:sleeping_snorlax_option_2_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:sleeping_snorlax_option_3_label",
- buttonTooltip: "mysteryEncounter:sleeping_snorlax_option_3_tooltip",
- disabledTooltip: "mysteryEncounter:sleeping_snorlax_option_3_disabled_tooltip"
- }
- ]
- }
-};
diff --git a/src/data/mystery-encounters/dialogue/training-session-dialogue.ts b/src/data/mystery-encounters/dialogue/training-session-dialogue.ts
deleted file mode 100644
index 9f49fc389b62..000000000000
--- a/src/data/mystery-encounters/dialogue/training-session-dialogue.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import MysteryEncounterDialogue from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-
-export const TrainingSessionDialogue: MysteryEncounterDialogue = {
- intro: [
- {
- text: "mysteryEncounter:training_session_intro_message"
- }
- ],
- encounterOptionsDialogue: {
- title: "mysteryEncounter:training_session_title",
- description: "mysteryEncounter:training_session_description",
- query: "mysteryEncounter:training_session_query",
- options: [
- {
- buttonLabel: "mysteryEncounter:training_session_option_1_label",
- buttonTooltip: "mysteryEncounter:training_session_option_1_tooltip",
- selected: [
- {
- text: "mysteryEncounter:training_session_option_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:training_session_option_2_label",
- buttonTooltip: "mysteryEncounter:training_session_option_2_tooltip",
- secondOptionPrompt: "mysteryEncounter:training_session_option_2_select_prompt",
- selected: [
- {
- text: "mysteryEncounter:training_session_option_selected_message"
- }
- ]
- },
- {
- buttonLabel: "mysteryEncounter:training_session_option_3_label",
- buttonTooltip: "mysteryEncounter:training_session_option_3_tooltip",
- secondOptionPrompt: "mysteryEncounter:training_session_option_3_select_prompt",
- selected: [
- {
- text: "mysteryEncounter:training_session_option_selected_message"
- }
- ]
- }
- ]
- },
- outro: [
- {
- text: "mysteryEncounter:training_session_outro_win"
- }
- ]
-};
diff --git a/src/data/mystery-encounters/fight-or-flight.ts b/src/data/mystery-encounters/fight-or-flight.ts
deleted file mode 100644
index 90cc57bbc137..000000000000
--- a/src/data/mystery-encounters/fight-or-flight.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import BattleScene from "../../battle-scene";
-import {ModifierTier} from "#app/modifier/modifier-tier";
-import {
- EnemyPartyConfig,
- initBattleWithEnemyConfig,
- leaveEncounterWithoutBattle, queueEncounterMessage,
- setCustomEncounterRewards,
- showEncounterText
-} from "#app/data/mystery-encounters/mystery-encounter-utils";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import {WaveCountRequirement} from "../mystery-encounter-requirements";
-import {MysteryEncounterOptionBuilder} from "../mystery-encounter-option";
-import {
- getPartyLuckValue,
- getPlayerModifierTypeOptions,
- ModifierPoolType,
- ModifierTypeOption,
- regenerateModifierPoolThresholds
-} from "#app/modifier/modifier-type";
-import {BattlerTagType} from "#enums/battler-tag-type";
-import {StatChangePhase} from "#app/phases";
-import {BattleStat} from "#app/data/battle-stat";
-import Pokemon from "#app/field/pokemon";
-import {randSeedInt} from "#app/utils";
-
-export const FightOrFlightEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.FIGHT_OR_FLIGHT)
- .withEncounterTier(MysteryEncounterTier.COMMON)
- .withIntroSpriteConfigs([]) // Set in onInit()
- .withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
- .withCatchAllowed(true)
- .withHideWildIntroMessage(true)
- .withOnInit((scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
-
- // Calculate boss mon
- const bossSpecies = scene.arena.randomSpecies(scene.currentBattle.waveIndex, scene.currentBattle.waveIndex, 0, getPartyLuckValue(scene.getParty()), true);
- const config: EnemyPartyConfig = {
- levelAdditiveMultiplier: 1,
- pokemonConfigs: [{species: bossSpecies, isBoss: true}]
- };
- encounter.enemyPartyConfigs = [config];
-
- // Calculate item
- // 10-60 GREAT, 60-110 ULTRA, 110-160 ROGUE, 160-180 MASTER
- const tier = scene.currentBattle.waveIndex > 160 ? ModifierTier.MASTER : scene.currentBattle.waveIndex > 110 ? ModifierTier.ROGUE : scene.currentBattle.waveIndex > 60 ? ModifierTier.ULTRA : ModifierTier.GREAT;
- regenerateModifierPoolThresholds(scene.getParty(), ModifierPoolType.PLAYER, 0); // refresh player item pool
- const item = getPlayerModifierTypeOptions(1, scene.getParty(), [], { guaranteedModifierTiers: [tier]})[0];
- encounter.setDialogueToken("itemName", item.type.name);
- encounter.misc = item;
-
- encounter.spriteConfigs = [
- {
- spriteKey: item.type.iconImage,
- fileRoot: "items",
- hasShadow: false,
- x: 35,
- y: -5,
- scale: 0.75,
- isItem: true
- },
- {
- spriteKey: bossSpecies.speciesId.toString(),
- fileRoot: "pokemon",
- hasShadow: true,
- tint: 0.25,
- x: -5,
- repeat: true
- }
- ];
-
- return true;
- })
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Pick battle
- const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
- setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
- await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Pick steal
- const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
- setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
-
- const roll = randSeedInt(16);
- if (roll > 6) {
- // Noticed and attacked by boss, gets +1 to all stats at start of fight (62.5%)
- const config = scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0];
- config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
- config.pokemonConfigs[0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
- pokemon.scene.currentBattle.mysteryEncounter.setDialogueToken("enemyPokemon", pokemon.name);
- queueEncounterMessage(pokemon.scene, "mysteryEncounter:fight_or_flight_boss_enraged");
- pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1));
- };
- await showEncounterText(scene, "mysteryEncounter:fight_or_flight_option_2_bad_result");
- await initBattleWithEnemyConfig(scene, config);
- } else {
- // Steal item (37.5%)
- // Display result message then proceed to rewards
- await showEncounterText(scene, "mysteryEncounter:fight_or_flight_option_2_good_result")
- .then(() => leaveEncounterWithoutBattle(scene));
- }
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Leave encounter with no rewards or exp
- leaveEncounterWithoutBattle(scene, true);
- return true;
- })
- .build())
- .build();
diff --git a/src/data/mystery-encounters/mysterious-challengers.ts b/src/data/mystery-encounters/mysterious-challengers.ts
deleted file mode 100644
index eaaeffec9d02..000000000000
--- a/src/data/mystery-encounters/mysterious-challengers.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import BattleScene from "../../battle-scene";
-import { ModifierTier } from "#app/modifier/modifier-tier";
-import {modifierTypes} from "#app/modifier/modifier-type";
-import { EnemyPartyConfig, initBattleWithEnemyConfig, setCustomEncounterRewards } from "#app/data/mystery-encounters/mystery-encounter-utils";
-import { MysteryEncounterType } from "#enums/mystery-encounter-type";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
-import { WaveCountRequirement } from "../mystery-encounter-requirements";
-import {
- trainerConfigs,
- TrainerPartyCompoundTemplate,
- TrainerPartyTemplate,
- trainerPartyTemplates
-} from "#app/data/trainer-config";
-import * as Utils from "../../utils";
-import {PartyMemberStrength} from "#enums/party-member-strength";
-
-export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS)
- .withEncounterTier(MysteryEncounterTier.UNCOMMON)
- .withIntroSpriteConfigs([]) // These are set in onInit()
- .withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
- .withOnInit((scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- // Calculates what trainers are available for battle in the encounter
-
- // Normal difficulty trainer is randomly pulled from biome
- const normalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
- const normalConfig = trainerConfigs[normalTrainerType].copy();
- let female = false;
- if (normalConfig.hasGenders) {
- female = !!(Utils.randSeedInt(2));
- }
- const normalSpriteKey = normalConfig.getSpriteKey(female, normalConfig.doubleOnly);
- encounter.enemyPartyConfigs.push({
- trainerConfig: normalConfig,
- female: female
- });
-
- // Hard difficulty trainer is another random trainer, but with AVERAGE_BALANCED config
- // Number of mons is based off wave: 1-20 is 2, 20-40 is 3, etc. capping at 6 after wave 100
- const hardTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex);
- const hardTemplate = new TrainerPartyCompoundTemplate(
- new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, false, true),
- new TrainerPartyTemplate(Math.min(Math.ceil(scene.currentBattle.waveIndex / 20), 5), PartyMemberStrength.AVERAGE, false, true));
- const hardConfig = trainerConfigs[hardTrainerType].copy();
- hardConfig.setPartyTemplates(hardTemplate);
- female = false;
- if (hardConfig.hasGenders) {
- female = !!(Utils.randSeedInt(2));
- }
- const hardSpriteKey = hardConfig.getSpriteKey(female, hardConfig.doubleOnly);
- encounter.enemyPartyConfigs.push({
- trainerConfig: hardConfig,
- levelAdditiveMultiplier: 0.5,
- female: female,
- });
-
- // Brutal trainer is pulled from pool of boss trainers (gym leaders) for the biome
- // They are given an E4 template team, so will be stronger than usual boss encounter and always have 6 mons
- const brutalTrainerType = scene.arena.randomTrainerType(scene.currentBattle.waveIndex, true);
- const e4Template = trainerPartyTemplates.ELITE_FOUR;
- const brutalConfig = trainerConfigs[brutalTrainerType].copy();
- brutalConfig.setPartyTemplates(e4Template);
- brutalConfig.partyTemplateFunc = null; // Overrides gym leader party template func
- female = false;
- if (brutalConfig.hasGenders) {
- female = !!(Utils.randSeedInt(2));
- }
- const brutalSpriteKey = brutalConfig.getSpriteKey(female, brutalConfig.doubleOnly);
- encounter.enemyPartyConfigs.push({
- trainerConfig: brutalConfig,
- levelAdditiveMultiplier: 1.1,
- female: female
- });
-
- encounter.spriteConfigs = [
- {
- spriteKey: normalSpriteKey,
- fileRoot: "trainer",
- hasShadow: true,
- tint: 1
- },
- {
- spriteKey: hardSpriteKey,
- fileRoot: "trainer",
- hasShadow: true,
- tint: 1
- },
- {
- spriteKey: brutalSpriteKey,
- fileRoot: "trainer",
- hasShadow: true,
- tint: 1
- }
- ];
-
- return true;
- })
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- // Spawn standard trainer battle with memory mushroom reward
- const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
-
- setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
-
- // Seed offsets to remove possibility of different trainers having exact same teams
- let ret;
- scene.executeWithSeedOffset(() => {
- ret = initBattleWithEnemyConfig(scene, config);
- }, scene.currentBattle.waveIndex * 10);
- return ret;
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- // Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
- const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
-
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true });
-
- // Seed offsets to remove possibility of different trainers having exact same teams
- let ret;
- scene.executeWithSeedOffset(() => {
- ret = initBattleWithEnemyConfig(scene, config);
- }, scene.currentBattle.waveIndex * 100);
- return ret;
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- // Spawn brutal fight with ROGUE/ULTRA/GREAT reward (can improve with luck)
- const config: EnemyPartyConfig = encounter.enemyPartyConfigs[2];
-
- // To avoid player level snowballing from picking this option
- encounter.expMultiplier = 0.9;
-
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
-
- // Seed offsets to remove possibility of different trainers having exact same teams
- let ret;
- scene.executeWithSeedOffset(() => {
- ret = initBattleWithEnemyConfig(scene, config);
- }, scene.currentBattle.waveIndex * 1000);
- return ret;
- })
- .build())
- .build();
diff --git a/src/data/mystery-encounters/mysterious-chest.ts b/src/data/mystery-encounters/mysterious-chest.ts
deleted file mode 100644
index 25abcf1fe741..000000000000
--- a/src/data/mystery-encounters/mysterious-chest.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import BattleScene from "../../battle-scene";
-import { ModifierTier } from "#app/modifier/modifier-tier";
-import {
- getHighestLevelPlayerPokemon,
- koPlayerPokemon,
- leaveEncounterWithoutBattle,
- queueEncounterMessage,
- setCustomEncounterRewards,
- showEncounterText
-} from "#app/data/mystery-encounters/mystery-encounter-utils";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import { MysteryEncounterType } from "#enums/mystery-encounter-type";
-import {WaveCountRequirement} from "../mystery-encounter-requirements";
-import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
-import {GameOverPhase} from "#app/phases";
-import {randSeedInt} from "#app/utils";
-
-export const MysteriousChestEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.MYSTERIOUS_CHEST)
- .withEncounterTier(MysteryEncounterTier.COMMON)
- .withIntroSpriteConfigs([
- {
- spriteKey: "chest_blue",
- fileRoot: "mystery-encounters",
- hasShadow: true,
- x: 4,
- y: 8,
- disableAnimation: true // Re-enabled after option select
- }
- ])
- .withHideIntroVisuals(false)
- .withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 2 to 180
- .withOption(new MysteryEncounterOptionBuilder()
- .withPreOptionPhase(async (scene: BattleScene) => {
- // Play animation
- const introVisuals = scene.currentBattle.mysteryEncounter.introVisuals;
- introVisuals.spriteConfigs[0].disableAnimation = false;
- introVisuals.playAnim();
- })
- .withOptionPhase(async (scene: BattleScene) => {
- // Open the chest
- const roll = randSeedInt(100);
- if (roll > 60) {
- // Choose between 2 COMMON / 2 GREAT tier items (40%)
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.GREAT]});
- // Display result message then proceed to rewards
- queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_normal_result");
- leaveEncounterWithoutBattle(scene);
- } else if (roll > 40) {
- // Choose between 3 ULTRA tier items (20%)
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA]});
- // Display result message then proceed to rewards
- queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_good_result");
- leaveEncounterWithoutBattle(scene);
- } else if (roll > 36) {
- // Choose between 2 ROGUE tier items (4%)
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE]});
- // Display result message then proceed to rewards
- queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_great_result");
- leaveEncounterWithoutBattle(scene);
- } else if (roll > 35) {
- // Choose 1 MASTER tier item (1%)
- setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER]});
- // Display result message then proceed to rewards
- queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_amazing_result");
- leaveEncounterWithoutBattle(scene);
- } else {
- // Your highest level unfainted Pok�mon gets OHKO. Progress with no rewards (35%)
- const highestLevelPokemon = getHighestLevelPlayerPokemon(scene, true);
- koPlayerPokemon(highestLevelPokemon);
-
- scene.currentBattle.mysteryEncounter.setDialogueToken("pokeName", highestLevelPokemon.name);
- // Show which Pokemon was KOed, then leave encounter with no rewards
- // Does this synchronously so that game over doesn't happen over result message
- await showEncounterText(scene, "mysteryEncounter:mysterious_chest_option_1_bad_result")
- .then(() => {
- if (scene.getParty().filter(p => p.isAllowedInBattle()).length === 0) {
- // All pokemon fainted, game over
- scene.clearPhaseQueue();
- scene.unshiftPhase(new GameOverPhase(scene));
- } else {
- leaveEncounterWithoutBattle(scene);
- }
- });
- }
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Leave encounter with no rewards or exp
- leaveEncounterWithoutBattle(scene, true);
- return true;
- })
- .build())
- .build();
diff --git a/src/data/mystery-encounters/mystery-encounter-utils.ts b/src/data/mystery-encounters/mystery-encounter-utils.ts
deleted file mode 100644
index 2a69becf1efd..000000000000
--- a/src/data/mystery-encounters/mystery-encounter-utils.ts
+++ /dev/null
@@ -1,698 +0,0 @@
-import i18next from "i18next";
-import {BattleType} from "#app/battle";
-import BattleScene from "../../battle-scene";
-import PokemonSpecies, {getPokemonSpecies, speciesStarters} from "../pokemon-species";
-import {MysteryEncounterVariant} from "../mystery-encounter";
-import {Status, StatusEffect} from "../status-effect";
-import {TrainerConfig, trainerConfigs, TrainerSlot} from "../trainer-config";
-import Pokemon, {FieldPosition, PlayerPokemon} from "#app/field/pokemon";
-import Trainer, {TrainerVariant} from "../../field/trainer";
-import {PokemonExpBoosterModifier} from "#app/modifier/modifier";
-import {
- CustomModifierSettings,
- ModifierPoolType,
- ModifierTypeFunc,
- PokemonHeldItemModifierType,
- regenerateModifierPoolThresholds
-} from "#app/modifier/modifier-type";
-import {BattleEndPhase, EggLapsePhase, ModifierRewardPhase, TrainerVictoryPhase} from "#app/phases";
-import {MysteryEncounterBattlePhase, MysteryEncounterRewardsPhase} from "#app/phases/mystery-encounter-phase";
-import * as Utils from "../../utils";
-import {isNullOrUndefined} from "#app/utils";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
-import {TrainerType} from "#enums/trainer-type";
-import {Species} from "#enums/species";
-import {Type} from "#app/data/type";
-import {BattlerTagType} from "#enums/battler-tag-type";
-import PokemonData from "#app/system/pokemon-data";
-import {Biome} from "#enums/biome";
-import {biomeLinks} from "#app/data/biomes";
-import {EncounterSceneRequirement} from "#app/data/mystery-encounter-requirements";
-import {Mode} from "#app/ui/ui";
-import {PartyOption, PartyUiMode} from "#app/ui/party-ui-handler";
-import {OptionSelectConfig, OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
-
-/**
- *
- * Will never remove the player's last non-fainted Pokemon (if they only have 1)
- * Otherwise, picks a Pokemon completely at random and removes from the party
- * @param scene
- * @param isAllowedInBattle - default false. If true, only picks from unfainted mons. If there is only 1 unfainted mon left and doNotReturnLastAbleMon is also true, will return fainted mon
- * @param doNotReturnLastAbleMon - If true, will never return the last unfainted pokemon in the party. Useful when this function is being used to determine what Pokemon to remove from the party (Don't want to remove last unfainted)
- * @returns
- */
-export function getRandomPlayerPokemon(scene: BattleScene, isAllowedInBattle: boolean = false, doNotReturnLastAbleMon: boolean = false): PlayerPokemon {
- const party = scene.getParty();
- let chosenIndex: number;
- let chosenPokemon: PlayerPokemon;
- const unfaintedMons = party.filter(p => p.isAllowedInBattle());
- const faintedMons = party.filter(p => !p.isAllowedInBattle());
-
- if (doNotReturnLastAbleMon && unfaintedMons.length === 1) {
- chosenIndex = Utils.randSeedInt(faintedMons.length);
- chosenPokemon = faintedMons.at(chosenIndex);
- } else if (isAllowedInBattle) {
- chosenIndex = Utils.randSeedInt(unfaintedMons.length);
- chosenPokemon = unfaintedMons.at(chosenIndex);
- } else {
- chosenIndex = Utils.randSeedInt(party.length);
- chosenPokemon = party.at(chosenIndex);
- }
-
- return chosenPokemon;
-}
-
-export function getTokensFromScene(scene: BattleScene, reqs: EncounterSceneRequirement[]): Array<[RegExp, String]> {
- const arr = [];
- if (scene) {
- for (const req of reqs) {
- req.getDialogueToken(scene);
- }
- }
- return arr;
-}
-
-/**
- * Ties are broken by whatever mon is closer to the front of the party
- * @param scene
- * @param unfainted - default false. If true, only picks from unfainted mons.
- * @returns
- */
-export function getHighestLevelPlayerPokemon(scene: BattleScene, unfainted: boolean = false): PlayerPokemon {
- const party = scene.getParty();
- let pokemon: PlayerPokemon;
- party.every(p => {
- if (unfainted && p.isFainted()) {
- return true;
- }
-
- pokemon = pokemon ? pokemon?.level < p?.level ? p : pokemon : p;
- return true;
- });
-
- return pokemon;
-}
-
-/**
- * Ties are broken by whatever mon is closer to the front of the party
- * @param scene
- * @param unfainted - default false. If true, only picks from unfainted mons.
- * @returns
- */
-export function getLowestLevelPlayerPokemon(scene: BattleScene, unfainted: boolean = false): PlayerPokemon {
- const party = scene.getParty();
- let pokemon: PlayerPokemon;
- party.every(p => {
- if (unfainted && p.isFainted()) {
- return true;
- }
-
- pokemon = pokemon ? pokemon?.level > p?.level ? p : pokemon : p;
- return true;
- });
-
- return pokemon;
-}
-
-export function koPlayerPokemon(pokemon: PlayerPokemon) {
- pokemon.hp = 0;
- pokemon.trySetStatus(StatusEffect.FAINT);
- pokemon.updateInfo();
-}
-
-export function getTextWithEncounterDialogueTokens(scene: BattleScene, textKey: TemplateStringsArray | `mysteryEncounter:${string}`): string {
- if (isNullOrUndefined(textKey)) {
- return null;
- }
-
- let textString: string = i18next.t(textKey);
-
- const dialogueTokens = scene.currentBattle?.mysteryEncounter?.dialogueTokens;
-
- if (dialogueTokens) {
- dialogueTokens.forEach((value) => {
- textString = textString.replace(value[0], value[1]);
- });
- }
-
- return textString;
-}
-
-/**
- * Will queue a message in UI with injected encounter data tokens
- * @param scene
- * @param contentKey
- */
-export function queueEncounterMessage(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): void {
- const text: string = getTextWithEncounterDialogueTokens(scene, contentKey);
- scene.queueMessage(text, null, true);
-}
-
-/**
- * Will display a message in UI with injected encounter data tokens
- * @param scene
- * @param contentKey
- */
-export function showEncounterText(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): Promise {
- return new Promise(resolve => {
- const text: string = getTextWithEncounterDialogueTokens(scene, contentKey);
- scene.ui.showText(text, null, () => resolve(), 0, true);
- });
-}
-
-/**
- * Will display a dialogue (with speaker title) in UI with injected encounter data tokens
- * @param scene
- * @param textContentKey
- * @param speakerContentKey
- * @param callback
- */
-export function showEncounterDialogue(scene: BattleScene, textContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, speakerContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, callback?: Function) {
- const text: string = getTextWithEncounterDialogueTokens(scene, textContentKey);
- const speaker: string = getTextWithEncounterDialogueTokens(scene, speakerContentKey);
- scene.ui.showDialogue(text, speaker, null, callback, 0, 0);
-}
-
-/**
- *
- * NOTE: This returns ANY random species, including those locked behind eggs, etc.
- * @param starterTiers
- * @param excludedSpecies
- * @param types
- * @returns
- */
-export function getRandomSpeciesByStarterTier(starterTiers: number | [number, number], excludedSpecies?: Species[], types?: Type[]): Species {
- let min = starterTiers instanceof Array ? starterTiers[0] : starterTiers;
- let max = starterTiers instanceof Array ? starterTiers[1] : starterTiers;
-
- let filteredSpecies: [PokemonSpecies, number][] = Object.keys(speciesStarters)
- .map(s => [parseInt(s) as Species, speciesStarters[s] as number])
- .filter(s => getPokemonSpecies(s[0]) && !excludedSpecies.includes(s[0]))
- .map(s => [getPokemonSpecies(s[0]), s[1]]);
-
- if (!isNullOrUndefined(types) && types.length > 0) {
- filteredSpecies = filteredSpecies.filter(s => types.includes(s[0].type1) || types.includes(s[0].type2));
- }
-
- // If no filtered mons exist at specified starter tiers, will expand starter search range until there are
- // Starts by decrementing starter tier min until it is 0, then increments tier max up to 10
- let tryFilterStarterTiers: [PokemonSpecies, number][] = filteredSpecies.filter(s => (s[1] >= min && s[1] <= max));
- while (tryFilterStarterTiers.length === 0 && (min !== 0 && max !== 10)) {
- if (min > 0) {
- min--;
- } else {
- max++;
- }
-
- tryFilterStarterTiers = filteredSpecies.filter(s => s[1] >= min && s[1] <= max);
- }
-
- if (tryFilterStarterTiers.length > 0) {
- const index = Utils.randSeedInt(tryFilterStarterTiers.length);
- return Phaser.Math.RND.shuffle(tryFilterStarterTiers)[index][0].speciesId;
- }
-
- return Species.BULBASAUR;
-}
-
-export class EnemyPokemonConfig {
- species: PokemonSpecies;
- isBoss: boolean = false;
- bossSegments?: number;
- bossSegmentModifier?: number; // Additive to the determined segment number
- formIndex?: number;
- level?: number;
- modifierTypes?: PokemonHeldItemModifierType[];
- dataSource?: PokemonData;
- tags?: BattlerTagType[];
- mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
- status?: StatusEffect;
-}
-
-export class EnemyPartyConfig {
- levelAdditiveMultiplier?: number = 0; // Formula for enemy: level += waveIndex / 10 * levelAdditive
- doubleBattle?: boolean = false;
- trainerType?: TrainerType; // Generates trainer battle solely off trainer type
- trainerConfig?: TrainerConfig; // More customizable option for configuring trainer battle
- pokemonConfigs?: EnemyPokemonConfig[];
- female?: boolean; // True for female trainer, false for male
-}
-
-/**
- * Generates an enemy party for a mystery encounter battle
- * This will override and replace any standard encounter generation logic
- * Useful for tailoring specific battles to mystery encounters
- * @param scene - Battle Scene
- * @param partyConfig - Can pass various customizable attributes for the enemy party, see EnemyPartyConfig
- */
-export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig: EnemyPartyConfig): Promise {
- const loaded = false;
- const loadEnemyAssets = [];
-
- const battle = scene.currentBattle;
-
- let doubleBattle = partyConfig?.doubleBattle;
-
- // Trainer
- const trainerType = partyConfig?.trainerType;
- let trainerConfig = partyConfig?.trainerConfig;
- if (trainerType || trainerConfig) {
- scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.TRAINER_BATTLE;
- if (scene.currentBattle.trainer) {
- scene.currentBattle.trainer.setVisible(false);
- scene.currentBattle.trainer.destroy();
- }
-
- trainerConfig = partyConfig?.trainerConfig ? partyConfig?.trainerConfig : trainerConfigs[trainerType];
-
- const doubleTrainer = trainerConfig.doubleOnly || (trainerConfig.hasDouble && partyConfig.doubleBattle);
- doubleBattle = doubleTrainer;
- const trainerFemale = isNullOrUndefined(partyConfig.female) ? !!(Utils.randSeedInt(2)) : partyConfig.female;
- const newTrainer = new Trainer(scene, trainerConfig.trainerType, doubleTrainer ? TrainerVariant.DOUBLE : trainerFemale ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT, null, null, null, trainerConfig);
- newTrainer.x += 300;
- newTrainer.setVisible(false);
- scene.field.add(newTrainer);
- scene.currentBattle.trainer = newTrainer;
- loadEnemyAssets.push(newTrainer.loadAssets());
-
- battle.enemyLevels = scene.currentBattle.trainer.getPartyLevels(scene.currentBattle.waveIndex);
- } else {
- // Wild
- scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.WILD_BATTLE;
- battle.enemyLevels = new Array(partyConfig?.pokemonConfigs?.length > 0 ? partyConfig?.pokemonConfigs?.length : doubleBattle ? 2 : 1).fill(null).map(() => scene.currentBattle.getLevelForWave());
- }
-
- scene.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy());
- battle.enemyParty = [];
- battle.double = doubleBattle;
-
- // ME levels are modified by an additive value that scales with wave index
- // Base scaling: Every 10 waves, modifier gets +1 level
- // This can be amplified or counteracted by setting levelAdditiveMultiplier in config
- // levelAdditiveMultiplier value of 0.5 will halve the modifier scaling, 2 will double it, etc.
- // Leaving null/undefined will disable level scaling
- const mult = !isNullOrUndefined(partyConfig.levelAdditiveMultiplier) ? partyConfig.levelAdditiveMultiplier : 0;
- const additive = Math.max(Math.round((scene.currentBattle.waveIndex / 10) * mult), 0);
- battle.enemyLevels = battle.enemyLevels.map(level => level + additive);
-
- battle.enemyLevels.forEach((level, e) => {
- let enemySpecies;
- let dataSource;
- let isBoss = false;
- if (!loaded) {
- if (trainerType || trainerConfig) {
- battle.enemyParty[e] = battle.trainer.genPartyMember(e);
- } else {
- if (e < partyConfig?.pokemonConfigs?.length) {
- const config = partyConfig?.pokemonConfigs?.[e];
- level = config.level ? config.level : level;
- dataSource = config.dataSource;
- enemySpecies = config.species;
- isBoss = config.isBoss;
- if (isBoss) {
- scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.BOSS_BATTLE;
- }
- } else {
- enemySpecies = scene.randomSpecies(battle.waveIndex, level, true);
- }
-
- battle.enemyParty[e] = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, isBoss, dataSource);
- }
- }
-
- const enemyPokemon = scene.getEnemyParty()[e];
-
- if (e < (doubleBattle ? 2 : 1)) {
- enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]);
- enemyPokemon.resetSummonData();
- }
-
- if (!loaded) {
- scene.gameData.setPokemonSeen(enemyPokemon, true, !!(trainerType || trainerConfig));
- }
-
- if (e < partyConfig?.pokemonConfigs?.length) {
- const config = partyConfig?.pokemonConfigs?.[e];
-
- // Generate new id in case using data source
- if (config.dataSource) {
- enemyPokemon.id = Utils.randSeedInt(4294967296);
- }
-
- // Set form
- if (!isNullOrUndefined(config.formIndex)) {
- enemyPokemon.formIndex = config.formIndex;
- }
-
- // Set Boss
- if (config.isBoss) {
- let segments = !isNullOrUndefined(config.bossSegments) ? config.bossSegments : scene.getEncounterBossSegments(scene.currentBattle.waveIndex, level, enemySpecies, true);
- if (!isNullOrUndefined(config.bossSegmentModifier)) {
- segments += config.bossSegmentModifier;
- }
- enemyPokemon.setBoss(true, segments);
- }
-
- // Set Status
- if (partyConfig.pokemonConfigs[e].status) {
- // Default to cureturn 3 for sleep
- const cureTurn = partyConfig.pokemonConfigs[e].status === StatusEffect.SLEEP ? 3: null;
- enemyPokemon.status = new Status(partyConfig.pokemonConfigs[e].status, 0, cureTurn);
- }
-
- // Set tags
- if (config.tags?.length > 0) {
- const tags = config.tags;
- tags.forEach(tag => enemyPokemon.addTag(tag));
- // mysteryEncounterBattleEffects can be used IFF MYSTERY_ENCOUNTER_POST_SUMMON tag is applied
- enemyPokemon.summonData.mysteryEncounterBattleEffects = config.mysteryEncounterBattleEffects;
-
- // Requires re-priming summon data so that tags are not cleared on SummonPhase
- enemyPokemon.primeSummonData(enemyPokemon.summonData);
- }
-
- enemyPokemon.initBattleInfo();
- }
-
- loadEnemyAssets.push(enemyPokemon.loadAssets());
-
- console.log(enemyPokemon.name, enemyPokemon.species.speciesId, enemyPokemon.stats);
- });
-
- scene.pushPhase(new MysteryEncounterBattlePhase(scene));
-
- await Promise.all(loadEnemyAssets);
- battle.enemyParty.forEach((enemyPokemon_2, e_1) => {
- if (e_1 < (doubleBattle ? 2 : 1)) {
- enemyPokemon_2.setVisible(false);
- if (battle.double) {
- enemyPokemon_2.setFieldPosition(e_1 ? FieldPosition.RIGHT : FieldPosition.LEFT);
- }
- // Spawns at current visible field instead of on "next encounter" field (off screen to the left)
- enemyPokemon_2.x += 300;
- }
- });
- if (!loaded) {
- regenerateModifierPoolThresholds(scene.getEnemyField(), battle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD);
- const customModifiers = partyConfig?.pokemonConfigs?.map(config => config?.modifierTypes);
- scene.generateEnemyModifiers(customModifiers);
- }
-}
-
-/**
- * Will initialize reward phases to follow the mystery encounter
- * Can have shop displayed or skipped
- * @param scene - Battle Scene
- * @param customShopRewards - adds a shop phase with the specified rewards / reward tiers
- * @param nonShopRewards - will add a non-shop reward phase for each specified item/modifier (can happen in addition to a shop)
- * @param preRewardsCallback - can execute an arbitrary callback before the new phases if necessary (useful for updating items/party/injecting new phases before MysteryEncounterRewardsPhase)
- */
-export function setCustomEncounterRewards(scene: BattleScene, customShopRewards?: CustomModifierSettings, nonShopRewards?: ModifierTypeFunc[], preRewardsCallback?: Function) {
- scene.currentBattle.mysteryEncounter.doEncounterRewards = (scene: BattleScene) => {
- if (preRewardsCallback) {
- preRewardsCallback();
- }
-
- if (customShopRewards) {
- scene.unshiftPhase(new SelectModifierPhase(scene, 0, null, customShopRewards));
- } else {
- scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
- }
-
- if (nonShopRewards?.length > 0) {
- nonShopRewards.forEach((reward) => {
- scene.unshiftPhase(new ModifierRewardPhase(scene, reward));
- });
- } else {
- while (!isNullOrUndefined(scene.findPhase(p => p instanceof ModifierRewardPhase))) {
- scene.tryRemovePhase(p => p instanceof ModifierRewardPhase);
- }
- }
-
- return true;
- };
-}
-
-/**
- *
- * @param scene
- * @param onPokemonSelected - Any logic that needs to be performed when Pokemon is chosen
- * If a second option needs to be selected, onPokemonSelected should return a OptionSelectItem[] object
- * @param onPokemonNotSelected - Any logic that needs to be performed if no Pokemon is chosen
- */
-export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (pokemon: PlayerPokemon) => void | OptionSelectItem[], onPokemonNotSelected?: () => void): Promise {
- return new Promise(resolve => {
- // Open party screen to choose pokemon to train
- scene.ui.setMode(Mode.PARTY, PartyUiMode.SELECT, -1, (slotIndex: integer, option: PartyOption) => {
- if (slotIndex < scene.getParty().length) {
- scene.ui.setMode(Mode.MYSTERY_ENCOUNTER).then(() => {
- const pokemon = scene.getParty()[slotIndex];
- const secondaryOptions = onPokemonSelected(pokemon);
- if (!secondaryOptions) {
- scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.name);
- resolve(true);
- return;
- }
-
- // There is a second option to choose after selecting the Pokemon
- scene.ui.setMode(Mode.MESSAGE).then(() => {
- const displayOptions = () => {
- // Always appends a cancel option to bottom of options
- const fullOptions = secondaryOptions.map(option => {
- // Update handler to resolve promise
- const onSelect = option.handler;
- option.handler = () => {
- onSelect();
- scene.currentBattle.mysteryEncounter.setDialogueToken("selectedPokemon", pokemon.name);
- resolve(true);
- return true;
- };
- return option;
- }).concat({
- label: i18next.t("menu:cancel"),
- handler: () => {
- scene.ui.setMode(Mode.MYSTERY_ENCOUNTER);
- resolve(false);
- return true;
- },
- onHover: () => {
- scene.ui.showText("Return to encounter option select.");
- }
- });
-
- const config: OptionSelectConfig = {
- options: fullOptions,
- maxOptions: 7,
- yOffset: 0,
- supportHover: true
- };
- scene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
- };
-
- const textPromptKey = scene.currentBattle.mysteryEncounter.selectedOption.dialogue.secondOptionPrompt;
- if (!textPromptKey) {
- displayOptions();
- } else {
- const secondOptionSelectPrompt = getTextWithEncounterDialogueTokens(scene, textPromptKey);
- scene.ui.showText(secondOptionSelectPrompt, null, displayOptions, null, true);
- }
- });
- });
- } else {
- scene.ui.setMode(Mode.MYSTERY_ENCOUNTER).then(() => {
- if (onPokemonNotSelected) {
- onPokemonNotSelected();
- }
- resolve(false);
- });
- }
- });
- });
-}
-
-/**
- * Will initialize exp phases to follow the mystery encounter (in addition to any combat or other exp earned)
- * Exp earned will be a simple function that linearly scales with wave index, that can be increased or decreased by the expMultiplier
- * Exp Share will have no effect (so no accounting for what mon is "on the field")
- * Exp Balance will still function as normal
- * @param scene - Battle Scene
- * @param expMultiplier - default is 100, can be increased or decreased as desired
- */
-export function setEncounterExp(scene: BattleScene, expMultiplier: number = 100) {
- //const expBalanceModifier = scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
- const expVal = scene.currentBattle.waveIndex * expMultiplier;
- const pokemonExp = new Utils.NumberHolder(expVal);
- const partyMemberExp = [];
-
- const party = scene.getParty();
- party.forEach(pokemon => {
- scene.applyModifiers(PokemonExpBoosterModifier, true, pokemon, pokemonExp);
- partyMemberExp.push(Math.floor(pokemonExp.value));
- });
-
- // TODO
- //if (expBalanceModifier) {
- // let totalLevel = 0;
- // let totalExp = 0;
- // expPartyMembers.forEach((expPartyMember, epm) => {
- // totalExp += partyMemberExp[epm];
- // totalLevel += expPartyMember.level;
- // });
-
- // const medianLevel = Math.floor(totalLevel / expPartyMembers.length);
-
- // const recipientExpPartyMemberIndexes = [];
- // expPartyMembers.forEach((expPartyMember, epm) => {
- // if (expPartyMember.level <= medianLevel) {
- // recipientExpPartyMemberIndexes.push(epm);
- // }
- // });
-
- // const splitExp = Math.floor(totalExp / recipientExpPartyMemberIndexes.length);
-
- // expPartyMembers.forEach((_partyMember, pm) => {
- // partyMemberExp[pm] = Phaser.Math.Linear(partyMemberExp[pm], recipientExpPartyMemberIndexes.indexOf(pm) > -1 ? splitExp : 0, 0.2 * expBalanceModifier.getStackCount());
- // });
- //}
-}
-
-/**
- * Can be used to exit an encounter without any battles or followup
- * Will skip any shops and rewards, and queue the next encounter phase as normal
- * @param scene
- * @param addHealPhase - when true, will add a shop phase to end of encounter with 0 rewards but healing items are available
- */
-export function leaveEncounterWithoutBattle(scene: BattleScene, addHealPhase: boolean = false) {
- scene.currentBattle.mysteryEncounter.encounterVariant = MysteryEncounterVariant.NO_BATTLE;
- scene.clearPhaseQueue();
- scene.clearPhaseQueueSplice();
- handleMysteryEncounterVictory(scene, addHealPhase);
-}
-
-export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase: boolean = false) {
- if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.NO_BATTLE) {
- scene.pushPhase(new EggLapsePhase(scene));
- scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
- } else if (!scene.getEnemyParty().find(p => scene.currentBattle.mysteryEncounter.encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) {
- scene.pushPhase(new BattleEndPhase(scene));
- if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
- scene.pushPhase(new TrainerVictoryPhase(scene));
- }
- if (scene.gameMode.isEndless || !scene.gameMode.isWaveFinal(scene.currentBattle.waveIndex)) {
- scene.pushPhase(new EggLapsePhase(scene));
- scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
- }
- }
-}
-
-/**
- * TODO: remove once encounter spawn rate is finalized
- * Just a helper function to calculate aggregate stats for MEs in a Classic run
- * @param scene
- * @param baseSpawnWeight
- */
-export function calculateMEAggregateStats(scene: BattleScene, baseSpawnWeight: number) {
- const numRuns = 1000;
- let run = 0;
- const targetEncountersPerRun = 15;
-
- const calculateNumEncounters = (): number[] => {
- let encounterRate = baseSpawnWeight;
- const numEncounters = [0, 0, 0, 0];
- let currentBiome = Biome.TOWN;
- let currentArena = scene.newArena(currentBiome);
- for (let i = 10; i < 180; i++) {
- // Boss
- if (i % 10 === 0) {
- continue;
- }
-
- // New biome
- if (i % 10 === 1) {
- if (Array.isArray(biomeLinks[currentBiome])) {
- let biomes: Biome[];
- scene.executeWithSeedOffset(() => {
- biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
- .filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
- .map(b => !Array.isArray(b) ? b : b[0]);
- }, i);
- currentBiome = biomes[Utils.randSeedInt(biomes.length)];
- } else if (biomeLinks.hasOwnProperty(currentBiome)) {
- currentBiome = (biomeLinks[currentBiome] as Biome);
- } else {
- if (!(i % 50)) {
- currentBiome = Biome.END;
- } else {
- currentBiome = scene.generateRandomBiome(i);
- }
- }
-
- currentArena = scene.newArena(currentBiome);
- }
-
- // Fixed battle
- if (scene.gameMode.isFixedBattle(i)) {
- continue;
- }
-
- // Trainer
- if (scene.gameMode.isWaveTrainer(i, currentArena)) {
- continue;
- }
-
- // Otherwise, roll encounter
-
- const roll = Utils.randSeedInt(256);
-
- // If total number of encounters is lower than expected for the run, slightly favor a new encounter
- // Do the reverse as well
- const expectedEncountersByFloor = targetEncountersPerRun / (180 - 10) * i;
- const currentRunDiffFromAvg = expectedEncountersByFloor - numEncounters.reduce((a, b) => a + b);
- const favoredEncounterRate = encounterRate + currentRunDiffFromAvg * 5;
-
- if (roll < favoredEncounterRate) {
- encounterRate = baseSpawnWeight;
-
- // Calculate encounter rarity
- // Common / Uncommon / Rare / Super Rare (base is out of 128)
- const tierWeights = [61, 40, 21, 6];
-
- // Adjust tier weights by currently encountered events (pity system that lowers odds of multiple common/uncommons)
- tierWeights[0] = tierWeights[0] - 6 * numEncounters[0];
- tierWeights[1] = tierWeights[1] - 4 * numEncounters[1];
-
- const totalWeight = tierWeights.reduce((a, b) => a + b);
- const tierValue = Utils.randSeedInt(totalWeight);
- const commonThreshold = totalWeight - tierWeights[0]; // 64 - 32 = 32
- const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1]; // 64 - 32 - 16 = 16
- const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2]; // 64 - 32 - 16 - 10 = 6
-
- tierValue > commonThreshold ? ++numEncounters[0] : tierValue > uncommonThreshold ? ++numEncounters[1] : tierValue > rareThreshold ? ++numEncounters[2] : ++numEncounters[3];
- } else {
- encounterRate++;
- }
- }
-
- return numEncounters;
- };
-
- const runs = [];
- while (run < numRuns) {
- scene.executeWithSeedOffset(() => {
- const numEncounters = calculateNumEncounters();
- runs.push(numEncounters);
- }, 1000 * run);
- run++;
- }
-
- const n = runs.length;
- const totalEncountersInRun = runs.map(run => run.reduce((a, b) => a + b));
- const totalMean = totalEncountersInRun.reduce((a, b) => a + b) / n;
- const totalStd = Math.sqrt(totalEncountersInRun.map(x => Math.pow(x - totalMean, 2)).reduce((a, b) => a + b) / n);
- const commonMean = runs.reduce((a, b) => a + b[0], 0) / n;
- const uncommonMean = runs.reduce((a, b) => a + b[1], 0) / n;
- const rareMean = runs.reduce((a, b) => a + b[2], 0) / n;
- const superRareMean = runs.reduce((a, b) => a + b[3], 0) / n;
-
- console.log(`Starting weight: ${baseSpawnWeight}\nAverage MEs per run: ${totalMean}\nStandard Deviation: ${totalStd}\nAvg Commons: ${commonMean}\nAvg Uncommons: ${uncommonMean}\nAvg Rares: ${rareMean}\nAvg Super Rares: ${superRareMean}`);
-}
diff --git a/src/data/mystery-encounters/mystery-encounters.ts b/src/data/mystery-encounters/mystery-encounters.ts
deleted file mode 100644
index 1a0f6f2a1ceb..000000000000
--- a/src/data/mystery-encounters/mystery-encounters.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-import MysteryEncounter from "../mystery-encounter";
-import {DarkDealEncounter} from "./dark-deal";
-import {MysteriousChallengersEncounter} from "./mysterious-challengers";
-import {MysteriousChestEncounter} from "./mysterious-chest";
-import {FightOrFlightEncounter} from "#app/data/mystery-encounters/fight-or-flight";
-import {TrainingSessionEncounter} from "#app/data/mystery-encounters/training-session";
-import { Biome } from "#app/enums/biome";
-import { SleepingSnorlaxEncounter } from "./sleeping-snorlax";
-import { MysteryEncounterType } from "#enums/mystery-encounter-type";
-
-export const BASE_MYSTERY_ENCOUNTER_WEIGHT = 19;
-export const AVERAGE_ENCOUNTERS_PER_RUN_TARGET = 15;
-
-export const allMysteryEncounters : {[encounterType:string]: MysteryEncounter} = {};
-
-// Add MysteryEncounterType to biomes to enable it exclusively for those biomes
-// To enable an encounter in all biomes, do not add to this map
-export const mysteryEncountersByBiome = new Map([
- [Biome.TOWN, [
- ]],
- [Biome.PLAINS,[
-
- ]],
- [Biome.GRASS, [
- MysteryEncounterType.SLEEPING_SNORLAX
- ]],
- [Biome.TALL_GRASS, [
-
- ]],
- [Biome.METROPOLIS, [
-
- ]],
- [Biome.FOREST, [
- MysteryEncounterType.SLEEPING_SNORLAX
- ]],
-
- [Biome.SEA, [
-
- ]],
- [Biome.SWAMP, [
-
- ]],
- [Biome.BEACH, [
-
- ]],
- [Biome.LAKE, [
-
- ]],
- [Biome.SEABED, [
-
- ]],
- [Biome.MOUNTAIN, [
- MysteryEncounterType.SLEEPING_SNORLAX
- ]],
- [Biome.BADLANDS, [
-
- ]],
- [Biome.CAVE, [
- MysteryEncounterType.SLEEPING_SNORLAX
- ]],
- [Biome.DESERT, [
-
- ]],
- [Biome.ICE_CAVE, [
-
- ]],
- [Biome.MEADOW, [
-
- ]],
- [Biome.POWER_PLANT, [
-
- ]],
- [Biome.VOLCANO, [
-
- ]],
- [Biome.GRAVEYARD, [
-
- ]],
- [Biome.DOJO, [
-
- ]],
- [Biome.FACTORY, [
-
- ]],
- [Biome.RUINS, [
-
- ]],
- [Biome.WASTELAND, [
-
- ]],
- [Biome.ABYSS, [
-
- ]],
- [Biome.SPACE, [
-
- ]],
- [Biome.CONSTRUCTION_SITE, [
-
- ]],
- [Biome.JUNGLE, [
-
- ]],
- [Biome.FAIRY_CAVE, [
-
- ]],
- [Biome.TEMPLE, [
-
- ]],
- [Biome.SLUM, [
-
- ]],
- [Biome.SNOWY_FOREST, [
-
- ]],
- [Biome.ISLAND, [
-
- ]],
- [Biome.LABORATORY, [
-
- ]]
-]);
-
-// Only add your MysterEncounter here if you want it to be in every biome.
-// We recommend designing biome-specific encounters for better flavor and variance
-export function initMysteryEncounters() {
- allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHALLENGERS] = MysteriousChallengersEncounter;
- allMysteryEncounters[MysteryEncounterType.MYSTERIOUS_CHEST] = MysteriousChestEncounter;
- allMysteryEncounters[MysteryEncounterType.DARK_DEAL] = DarkDealEncounter;
- allMysteryEncounters[MysteryEncounterType.FIGHT_OR_FLIGHT] = FightOrFlightEncounter;
- allMysteryEncounters[MysteryEncounterType.TRAINING_SESSION] = TrainingSessionEncounter;
- allMysteryEncounters[MysteryEncounterType.SLEEPING_SNORLAX] = SleepingSnorlaxEncounter;
-
- // Append encounters that can occur in any biome to biome map
- const anyBiomeEncounters: MysteryEncounterType[] = Object.keys(MysteryEncounterType).filter(e => !isNaN(Number(e))).map(k => Number(k) as MysteryEncounterType);
- mysteryEncountersByBiome.forEach(biomeEncounters => {
- biomeEncounters.forEach(e => {
- if (anyBiomeEncounters.includes(e)) {
- anyBiomeEncounters.splice(anyBiomeEncounters.indexOf(e), 1);
- }
- });
- });
-
- mysteryEncountersByBiome.forEach(biomeEncounters => biomeEncounters.push(...anyBiomeEncounters));
-}
diff --git a/src/data/mystery-encounters/sleeping-snorlax.ts b/src/data/mystery-encounters/sleeping-snorlax.ts
deleted file mode 100644
index 56baa4ea1e7b..000000000000
--- a/src/data/mystery-encounters/sleeping-snorlax.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import BattleScene from "../../battle-scene";
-import {
- EnemyPartyConfig,
- EnemyPokemonConfig,
- initBattleWithEnemyConfig,
- leaveEncounterWithoutBattle, queueEncounterMessage,
- setCustomEncounterRewards
-} from "./mystery-encounter-utils";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import * as Utils from "../../utils";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import {MoveRequirement, WaveCountRequirement} from "../mystery-encounter-requirements";
-import {MysteryEncounterOptionBuilder} from "../mystery-encounter-option";
-import {
- ModifierTypeGenerator,
- ModifierTypeOption,
- modifierTypes
-} from "#app/modifier/modifier-type";
-import { getPokemonSpecies } from "../pokemon-species";
-import { Species } from "#enums/species";
-import { Status, StatusEffect } from "../status-effect";
-import { Moves } from "#enums/moves";
-import { BerryType } from "#enums/berry-type";
-
-export const SleepingSnorlaxEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.SLEEPING_SNORLAX)
- .withEncounterTier(MysteryEncounterTier.RARE)
- .withIntroSpriteConfigs([
- {
- spriteKey: Species.SNORLAX.toString(),
- fileRoot: "pokemon",
- hasShadow: true,
- tint: 0.25,
- repeat: true
- }
- ])
- .withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
- .withCatchAllowed(true)
- .withHideWildIntroMessage(true)
- .withOnInit((scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- console.log(encounter);
-
- // Calculate boss mon
- const bossSpecies = getPokemonSpecies(Species.SNORLAX);
- const pokemonConfig: EnemyPokemonConfig = {
- species: bossSpecies,
- isBoss: true,
- status: StatusEffect.SLEEP
- };
- const config: EnemyPartyConfig = {
- levelAdditiveMultiplier: 2,
- pokemonConfigs: [pokemonConfig]
- };
- encounter.enemyPartyConfigs = [config];
- return true;
- })
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- // Pick battle
- // TODO: do we want special rewards for this?
- // setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: true});
- await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withOptionPhase(async (scene: BattleScene) => {
- const instance = scene.currentBattle.mysteryEncounter;
- let roll:integer;
- scene.executeWithSeedOffset(() => {
- roll = Utils.randSeedInt(16, 0);
- }, scene.currentBattle.waveIndex);
- console.log(roll);
- if (roll > 4) {
- // Fall asleep and get a sitrus berry (75%)
- const p = instance.primaryPokemon;
- p.status = new Status(StatusEffect.SLEEP, 0, 3);
- p.updateInfo(true);
- const sitrus = (modifierTypes.BERRY?.() as ModifierTypeGenerator).generateType(scene.getParty(), [BerryType.SITRUS]);
-
- setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [new ModifierTypeOption(sitrus, 0)], fillRemaining: false});
- queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_bad_result");
- leaveEncounterWithoutBattle(scene);
- } else {
- // Heal to full (25%)
- for (const pokemon of scene.getParty()) {
- pokemon.hp = pokemon.getMaxHp();
- pokemon.resetStatus();
- for (const move of pokemon.moveset) {
- move.ppUsed = 0;
- }
- pokemon.updateInfo(true);
- }
-
- queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_good_result");
- leaveEncounterWithoutBattle(scene);
- }
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withPrimaryPokemonRequirement(new MoveRequirement([Moves.PLUCK, Moves.COVET, Moves.KNOCK_OFF, Moves.THIEF, Moves.TRICK, Moves.SWITCHEROO]))
- .withOptionPhase(async (scene: BattleScene) => {
- // Leave encounter with no rewards or exp
- setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false});
- queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_3_good_result");
- leaveEncounterWithoutBattle(scene);
- })
- .build())
- .build();
diff --git a/src/data/mystery-encounters/training-session.ts b/src/data/mystery-encounters/training-session.ts
deleted file mode 100644
index 9866a2785a11..000000000000
--- a/src/data/mystery-encounters/training-session.ts
+++ /dev/null
@@ -1,306 +0,0 @@
-import BattleScene from "../../battle-scene";
-import {
- EnemyPartyConfig,
- getTextWithEncounterDialogueTokens,
- initBattleWithEnemyConfig,
- selectPokemonForOption,
- setCustomEncounterRewards
-} from "#app/data/mystery-encounters/mystery-encounter-utils";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type";
-import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
-import {MysteryEncounterOptionBuilder} from "../mystery-encounter-option";
-import {WaveCountRequirement} from "../mystery-encounter-requirements";
-import {PlayerPokemon} from "#app/field/pokemon";
-import PokemonData from "#app/system/pokemon-data";
-import {randSeedShuffle} from "#app/utils";
-import {getNatureName, Nature} from "#app/data/nature";
-import {BattlerTagType} from "#enums/battler-tag-type";
-import {OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
-import {PokemonHeldItemModifier} from "#app/modifier/modifier";
-import {PokemonHeldItemModifierType} from "#app/modifier/modifier-type";
-import {Ability, allAbilities} from "#app/data/ability";
-import {speciesStarters} from "#app/data/pokemon-species";
-import {AbilityAttr} from "#app/system/game-data";
-import {Stat} from "#app/data/pokemon-stat";
-import {pokemonInfo} from "#app/locales/en/pokemon-info";
-
-export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBuilder()
- .withEncounterType(MysteryEncounterType.TRAINING_SESSION)
- .withEncounterTier(MysteryEncounterTier.RARE)
- .withIntroSpriteConfigs([
- {
- spriteKey: "training_gear",
- fileRoot: "mystery-encounters",
- hasShadow: true,
- y: 3
- }
- ])
- .withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
- .withHideWildIntroMessage(true)
- .withOption(new MysteryEncounterOptionBuilder()
- .withPreOptionPhase(async (scene: BattleScene): Promise => {
- const encounter = scene.currentBattle.mysteryEncounter;
- const onPokemonSelected = (pokemon: PlayerPokemon) => {
- encounter.misc = {
- playerPokemon: pokemon
- };
- };
-
- return selectPokemonForOption(scene, onPokemonSelected);
- })
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
-
- // Spawn light training session with chosen pokemon
- // Every 50 waves, add +1 boss segment, capping at 5
- const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 50), 5);
- const modifiers = new ModifiersHolder();
- const config = getEnemyConfig(scene, playerPokemon, segments, modifiers);
- scene.removePokemonFromPlayerParty(playerPokemon, false);
-
- const getIvName = (index: number) => {
- switch (index) {
- case Stat.HP:
- return pokemonInfo.Stat["HPshortened"];
- case Stat.ATK:
- return pokemonInfo.Stat["ATKshortened"];
- case Stat.DEF:
- return pokemonInfo.Stat["DEFshortened"];
- case Stat.SPATK:
- return pokemonInfo.Stat["SPATKshortened"];
- case Stat.SPDEF:
- return pokemonInfo.Stat["SPDEFshortened"];
- case Stat.SPD:
- return pokemonInfo.Stat["SPDshortened"];
- }
- };
-
- const onBeforeRewardsPhase = () => {
- encounter.setDialogueToken("stat1", "-");
- encounter.setDialogueToken("stat2", "-");
- // Add the pokemon back to party with IV boost
- const ivIndexes = [];
- playerPokemon.ivs.forEach((iv, index) => {
- if (iv < 31) {
- ivIndexes.push({iv: iv, index: index});
- }
- });
-
- // Improves 2 random non-maxed IVs
- // +10 if IV is < 10, +5 if between 10-20, and +3 if > 20
- // A 0-4 starting IV will cap in 6 encounters (assuming you always rolled that IV)
- // 5-14 starting IV caps in 5 encounters
- // 15-19 starting IV caps in 4 encounters
- // 20-24 starting IV caps in 3 encounters
- // 25-27 starting IV caps in 2 encounters
- let improvedCount = 0;
- while (ivIndexes.length > 0 && improvedCount < 2) {
- randSeedShuffle(ivIndexes);
- const ivToChange = ivIndexes.pop();
- let newVal = ivToChange.iv;
- if (improvedCount === 0) {
- encounter.setDialogueToken("stat1", getIvName(ivToChange.index));
- } else {
- encounter.setDialogueToken("stat2", getIvName(ivToChange.index));
- }
-
- // Corrects required encounter breakpoints to be continuous for all IV values
- if (ivToChange.iv <= 21 && ivToChange.iv - 1 % 5 === 0) {
- newVal += 1;
- }
-
- newVal += ivToChange.iv <= 10 ? 10 : ivToChange.iv <= 20 ? 5 : 3;
- newVal = Math.min(newVal, 31);
- playerPokemon.ivs[ivToChange.index] = newVal;
- improvedCount++;
- }
-
- if (improvedCount > 0) {
- playerPokemon.calculateStats();
- scene.gameData.updateSpeciesDexIvs(playerPokemon.species.getRootSpeciesId(true), playerPokemon.ivs);
- scene.gameData.setPokemonCaught(playerPokemon, false);
- }
-
- // Add pokemon and mods back
- scene.getParty().push(playerPokemon);
- for (const mod of modifiers.value) {
- scene.addModifier(mod, true, false, false, true);
- }
- scene.updateModifiers(true);
- scene.queueMessage(getTextWithEncounterDialogueTokens(scene, "mysteryEncounter:training_session_battle_finished_1"), null, true);
- };
-
- setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
-
- return initBattleWithEnemyConfig(scene, config);
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withPreOptionPhase(async (scene: BattleScene): Promise => {
- // Open menu for selecting pokemon and Nature
- const encounter = scene.currentBattle.mysteryEncounter;
- const natures = new Array(25).fill(null).map((val, i) => i as Nature);
- const onPokemonSelected = (pokemon: PlayerPokemon) => {
- // Return the options for nature selection
- return natures.map((nature: Nature) => {
- const option: OptionSelectItem = {
- label: getNatureName(nature, true, true, true, scene.uiTheme),
- handler: () => {
- // Pokemon and second option selected
- encounter.setDialogueToken("nature", getNatureName(nature));
- encounter.misc = {
- playerPokemon: pokemon,
- chosenNature: nature
- };
- return true;
- }
- };
- return option;
- });
- };
-
- return selectPokemonForOption(scene, onPokemonSelected);
- })
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
-
- // Spawn medium training session with chosen pokemon
- // Every 40 waves, add +1 boss segment, capping at 6
- const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 40), 6);
- const modifiers = new ModifiersHolder();
- const config = getEnemyConfig(scene, playerPokemon, segments, modifiers);
- scene.removePokemonFromPlayerParty(playerPokemon, false);
-
- const onBeforeRewardsPhase = () => {
- scene.queueMessage(getTextWithEncounterDialogueTokens(scene, "mysteryEncounter:training_session_battle_finished_2"), null, true);
- // Add the pokemon back to party with Nature change
- playerPokemon.setNature(encounter.misc.chosenNature);
- scene.gameData.setPokemonCaught(playerPokemon, false);
-
- // Add pokemon and mods back
- scene.getParty().push(playerPokemon);
- for (const mod of modifiers.value) {
- scene.addModifier(mod, true, false, false, true);
- }
- scene.updateModifiers(true);
- };
-
- setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
-
- return initBattleWithEnemyConfig(scene, config);
- })
- .build())
- .withOption(new MysteryEncounterOptionBuilder()
- .withPreOptionPhase(async (scene: BattleScene): Promise => {
- // Open menu for selecting pokemon and ability to learn
- const encounter = scene.currentBattle.mysteryEncounter;
- const onPokemonSelected = (pokemon: PlayerPokemon) => {
- // Return the options for ability selection
- const speciesForm = !!pokemon.getFusionSpeciesForm() ? pokemon.getFusionSpeciesForm() : pokemon.getSpeciesForm();
- const abilityCount = speciesForm.getAbilityCount();
- const abilities = new Array(abilityCount).fill(null).map((val, i) => allAbilities[speciesForm.getAbility(i)]);
- return abilities.map((ability: Ability, index) => {
- const option: OptionSelectItem = {
- label: ability.name,
- handler: () => {
- // Pokemon and ability selected
- encounter.setDialogueToken("ability", ability.name);
- encounter.misc = {
- playerPokemon: pokemon,
- abilityIndex: index
- };
- return true;
- },
- onHover: () => {
- scene.ui.showText(ability.description);
- }
- };
- return option;
- });
- };
-
- return selectPokemonForOption(scene, onPokemonSelected);
- })
- .withOptionPhase(async (scene: BattleScene) => {
- const encounter = scene.currentBattle.mysteryEncounter;
- const playerPokemon: PlayerPokemon = encounter.misc.playerPokemon;
-
- // Spawn hard training session with chosen pokemon
- // Every 30 waves, add +1 boss segment, capping at 6
- // Also starts with +1 to all stats
- const segments = Math.min(2 + Math.floor(scene.currentBattle.waveIndex / 30), 6);
- const modifiers = new ModifiersHolder();
- const config = getEnemyConfig(scene, playerPokemon, segments, modifiers);
- config.pokemonConfigs[0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
- scene.removePokemonFromPlayerParty(playerPokemon, false);
-
- const onBeforeRewardsPhase = () => {
- scene.queueMessage(getTextWithEncounterDialogueTokens(scene, "mysteryEncounter:training_session_battle_finished_3"), null, true);
- // Add the pokemon back to party with ability change
- const abilityIndex = encounter.misc.abilityIndex;
- if (!!playerPokemon.getFusionSpeciesForm()) {
- playerPokemon.fusionAbilityIndex = abilityIndex;
- if (speciesStarters.hasOwnProperty(playerPokemon.fusionSpecies.speciesId)) {
- scene.gameData.starterData[playerPokemon.fusionSpecies.speciesId].abilityAttr |= abilityIndex !== 1 || playerPokemon.fusionSpecies.ability2
- ? Math.pow(2, playerPokemon.fusionAbilityIndex)
- : AbilityAttr.ABILITY_HIDDEN;
- }
- } else {
- playerPokemon.abilityIndex = abilityIndex;
- if (speciesStarters.hasOwnProperty(playerPokemon.species.speciesId)) {
- scene.gameData.starterData[playerPokemon.species.speciesId].abilityAttr |= abilityIndex !== 1 || playerPokemon.species.ability2
- ? Math.pow(2, playerPokemon.abilityIndex)
- : AbilityAttr.ABILITY_HIDDEN;
- }
- }
-
- playerPokemon.getAbility();
- playerPokemon.calculateStats();
- scene.gameData.setPokemonCaught(playerPokemon, false);
-
- // Add pokemon and mods back
- scene.getParty().push(playerPokemon);
- for (const mod of modifiers.value) {
- scene.addModifier(mod, true, false, false, true);
- }
- scene.updateModifiers(true);
- };
-
- setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
-
- return initBattleWithEnemyConfig(scene, config);
- })
- .build())
- .build();
-
-function getEnemyConfig(scene: BattleScene, playerPokemon: PlayerPokemon, segments: number, modifiers: ModifiersHolder): EnemyPartyConfig {
- playerPokemon.resetSummonData();
-
- // Passes modifiers by reference
- modifiers.value = scene.findModifiers(m => m instanceof PokemonHeldItemModifier
- && (m as PokemonHeldItemModifier).pokemonId === playerPokemon.id) as PokemonHeldItemModifier[];
- const modifierTypes = modifiers.value.map(mod => mod.type) as PokemonHeldItemModifierType[];
-
- const data = new PokemonData(playerPokemon);
- return {
- pokemonConfigs: [
- {
- species: playerPokemon.species,
- isBoss: true,
- bossSegments: segments,
- formIndex: playerPokemon.formIndex,
- level: playerPokemon.level,
- dataSource: data,
- modifierTypes: modifierTypes
- }
- ]
- };
-}
-
-class ModifiersHolder {
- public value: PokemonHeldItemModifier[] = [];
-
- constructor() {}
-}
diff --git a/src/data/pokemon-evolutions.ts b/src/data/pokemon-evolutions.ts
index 1c2b903de75b..1fb1f7db5fd4 100644
--- a/src/data/pokemon-evolutions.ts
+++ b/src/data/pokemon-evolutions.ts
@@ -1145,11 +1145,6 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.PAWMOT, 32, null, null)
],
[Species.TANDEMAUS]: [
- new SpeciesFormEvolution(Species.MAUSHOLD, "", "three", 25, null, new SpeciesEvolutionCondition(p => {
- let ret = false;
- p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id);
- return ret;
- })),
new SpeciesEvolution(Species.MAUSHOLD, 25, null, null)
],
[Species.FIDOUGH]: [
diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts
index b734abe190d9..ae1532f0be01 100644
--- a/src/data/pokemon-forms.ts
+++ b/src/data/pokemon-forms.ts
@@ -371,9 +371,6 @@ export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: Specie
if (isRevert) {
return `${prefix}${pokemon.name} reverted\nto its original form!`;
}
- if (pokemon.species.speciesId === Species.MIMIKYU) {
- return "Its disguise served it as a decoy!";
- }
return `${prefix}${preName} changed form!`;
}
diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts
index a2eba88a5040..2b488f330c45 100644
--- a/src/data/pokemon-species.ts
+++ b/src/data/pokemon-species.ts
@@ -2431,8 +2431,8 @@ export function initSpecies() {
new PokemonSpecies(Species.PAWMOT, 9, false, false, false, "Hands-On Pokémon", Type.ELECTRIC, Type.FIGHTING, 0.9, 41, Abilities.VOLT_ABSORB, Abilities.NATURAL_CURE, Abilities.IRON_FIST, 490, 70, 115, 70, 70, 60, 105, 45, 50, 245, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.TANDEMAUS, 9, false, false, false, "Couple Pokémon", Type.NORMAL, null, 0.3, 1.8, Abilities.RUN_AWAY, Abilities.PICKUP, Abilities.OWN_TEMPO, 305, 50, 50, 45, 40, 45, 75, 150, 50, 61, GrowthRate.FAST, null, false),
new PokemonSpecies(Species.MAUSHOLD, 9, false, false, false, "Family Pokémon", Type.NORMAL, null, 0.3, 2.3, Abilities.FRIEND_GUARD, Abilities.CHEEK_POUCH, Abilities.TECHNICIAN, 470, 74, 75, 70, 65, 75, 111, 75, 50, 165, GrowthRate.FAST, null, false, false,
- new PokemonForm("Family of Four", "four", Type.NORMAL, null, 0.3, 2.8, Abilities.FRIEND_GUARD, Abilities.CHEEK_POUCH, Abilities.TECHNICIAN, 470, 74, 75, 70, 65, 75, 111, 75, 50, 165),
- new PokemonForm("Family of Three", "three", Type.NORMAL, null, 0.3, 2.3, Abilities.FRIEND_GUARD, Abilities.CHEEK_POUCH, Abilities.TECHNICIAN, 470, 74, 75, 70, 65, 75, 111, 75, 50, 165),
+ new PokemonForm("Family of Four", "four", Type.NORMAL, null, 0.3, 2.3, Abilities.FRIEND_GUARD, Abilities.CHEEK_POUCH, Abilities.TECHNICIAN, 470, 74, 75, 70, 65, 75, 111, 75, 50, 165),
+ new PokemonForm("Family of Three", "three", Type.NORMAL, null, 0.3, 2.8, Abilities.FRIEND_GUARD, Abilities.CHEEK_POUCH, Abilities.TECHNICIAN, 470, 74, 75, 70, 65, 75, 111, 75, 50, 165),
),
new PokemonSpecies(Species.FIDOUGH, 9, false, false, false, "Puppy Pokémon", Type.FAIRY, null, 0.3, 10.9, Abilities.OWN_TEMPO, Abilities.NONE, Abilities.KLUTZ, 312, 37, 55, 70, 30, 55, 65, 190, 50, 62, GrowthRate.MEDIUM_SLOW, 50, false),
new PokemonSpecies(Species.DACHSBUN, 9, false, false, false, "Dog Pokémon", Type.FAIRY, null, 0.5, 14.9, Abilities.WELL_BAKED_BODY, Abilities.NONE, Abilities.AROMA_VEIL, 477, 57, 80, 115, 50, 80, 95, 90, 50, 167, GrowthRate.MEDIUM_SLOW, 50, false),
diff --git a/src/data/terrain.ts b/src/data/terrain.ts
index f7324c28b93b..e396c693c4ed 100644
--- a/src/data/terrain.ts
+++ b/src/data/terrain.ts
@@ -5,7 +5,6 @@ import * as Utils from "../utils";
import { IncrementMovePriorityAbAttr, applyAbAttrs } from "./ability";
import { ProtectAttr } from "./move";
import { BattlerIndex } from "#app/battle.js";
-import i18next from "i18next";
export enum TerrainType {
NONE,
@@ -68,22 +67,6 @@ export class Terrain {
}
}
-export function getTerrainName(terrainType: TerrainType): string {
- switch (terrainType) {
- case TerrainType.MISTY:
- return i18next.t("terrain:misty");
- case TerrainType.ELECTRIC:
- return i18next.t("terrain:electric");
- case TerrainType.GRASSY:
- return i18next.t("terrain:grassy");
- case TerrainType.PSYCHIC:
- return i18next.t("terrain:psychic");
- }
-
- return "";
-}
-
-
export function getTerrainColor(terrainType: TerrainType): [ integer, integer, integer ] {
switch (terrainType) {
case TerrainType.MISTY:
diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts
index fa9d0fdd55ab..8a25406fc5af 100644
--- a/src/data/trainer-config.ts
+++ b/src/data/trainer-config.ts
@@ -810,63 +810,6 @@ export class TrainerConfig {
}
});
}
-
- copy(): TrainerConfig {
- let copy = new TrainerConfig(this.trainerType);
- copy = this.trainerTypeDouble ? copy.setDoubleTrainerType(this.trainerTypeDouble) : copy;
- copy = this.name ? copy.setName(this.name) : copy;
- copy = this.hasGenders ? copy.setHasGenders(this.nameFemale, this.femaleEncounterBgm) : copy;
- copy = this.hasDouble ? copy.setHasDouble(this.nameDouble, this.doubleEncounterBgm) : copy;
- copy = this.title ? copy.setTitle(this.title) : copy;
- copy = this.titleDouble ? copy.setDoubleTitle(this.titleDouble) : copy;
- copy = this.hasCharSprite ? copy.setHasCharSprite() : copy;
- copy = this.doubleOnly ? copy.setDoubleOnly() : copy;
- copy = this.moneyMultiplier ? copy.setMoneyMultiplier(this.moneyMultiplier) : copy;
- copy = this.isBoss ? copy.setBoss() : copy;
- copy = this.hasStaticParty ? copy.setStaticParty() : copy;
- copy = this.useSameSeedForAllMembers ? copy.setUseSameSeedForAllMembers() : copy;
- copy = this.battleBgm ? copy.setBattleBgm(this.battleBgm) : copy;
- copy = this.encounterBgm ? copy.setEncounterBgm(this.encounterBgm) : copy;
- copy = this.victoryBgm ? copy.setVictoryBgm(this.victoryBgm) : copy;
- copy = this.genModifiersFunc ? copy.setGenModifiersFunc(this.genModifiersFunc) : copy;
-
- if (this.modifierRewardFuncs) {
- // Clones array instead of passing ref
- copy.modifierRewardFuncs = this.modifierRewardFuncs.slice(0);
- }
-
- if (this.partyTemplates) {
- copy.partyTemplates = this.partyTemplates.slice(0);
- }
-
- copy = this.partyTemplateFunc ? copy.setPartyTemplateFunc(this.partyTemplateFunc) : copy;
-
- if (this.partyMemberFuncs) {
- Object.keys(this.partyMemberFuncs).forEach((index) => {
- copy = copy.setPartyMemberFunc(parseInt(index, 10), this.partyMemberFuncs[index]);
- });
- }
-
- copy = this.speciesPools ? copy.setSpeciesPools(this.speciesPools) : copy;
- copy = this.speciesFilter ? copy.setSpeciesFilter(this.speciesFilter) : copy;
- if (this.specialtyTypes) {
- copy.specialtyTypes = this.specialtyTypes.slice(0);
- }
-
- copy.encounterMessages = this.encounterMessages?.slice(0);
- copy.victoryMessages = this.victoryMessages?.slice(0);
- copy.defeatMessages = this.defeatMessages?.slice(0);
-
- copy.femaleEncounterMessages = this.femaleEncounterMessages?.slice(0);
- copy.femaleVictoryMessages = this.femaleVictoryMessages?.slice(0);
- copy.femaleDefeatMessages = this.femaleDefeatMessages?.slice(0);
-
- copy.doubleEncounterMessages = this.doubleEncounterMessages?.slice(0);
- copy.doubleVictoryMessages = this.doubleVictoryMessages?.slice(0);
- copy.doubleDefeatMessages = this.doubleDefeatMessages?.slice(0);
-
- return copy;
- }
}
let t = 0;
diff --git a/src/data/weather.ts b/src/data/weather.ts
index f671c7548730..425dd3724f63 100644
--- a/src/data/weather.ts
+++ b/src/data/weather.ts
@@ -1,12 +1,12 @@
import { Biome } from "#enums/biome";
-import { getPokemonNameWithAffix } from "../messages";
+import { getPokemonMessage, getPokemonNameWithAffix } from "../messages";
import Pokemon from "../field/pokemon";
import { Type } from "./type";
import Move, { AttackMove } from "./move";
import * as Utils from "../utils";
import BattleScene from "../battle-scene";
import { SuppressWeatherEffectAbAttr } from "./ability";
-import { TerrainType, getTerrainName } from "./terrain";
+import { TerrainType } from "./terrain";
import i18next from "i18next";
export enum WeatherType {
@@ -216,34 +216,34 @@ export function getWeatherClearMessage(weatherType: WeatherType): string {
export function getTerrainStartMessage(terrainType: TerrainType): string {
switch (terrainType) {
case TerrainType.MISTY:
- return i18next.t("terrain:mistyStartMessage");
+ return "Mist swirled around the battlefield!";
case TerrainType.ELECTRIC:
- return i18next.t("terrain:electricStartMessage");
+ return "An electric current ran across the battlefield!";
case TerrainType.GRASSY:
- return i18next.t("terrain:grassyStartMessage");
+ return "Grass grew to cover the battlefield!";
case TerrainType.PSYCHIC:
- return i18next.t("terrain:psychicStartMessage");
+ return "The battlefield got weird!";
}
}
export function getTerrainClearMessage(terrainType: TerrainType): string {
switch (terrainType) {
case TerrainType.MISTY:
- return i18next.t("terrain:mistyClearMessage");
+ return "The mist disappeared from the battlefield.";
case TerrainType.ELECTRIC:
- return i18next.t("terrain:electricClearMessage");
+ return "The electricity disappeared from the battlefield.";
case TerrainType.GRASSY:
- return i18next.t("terrain:grassyClearMessage");
+ return "The grass disappeared from the battlefield.";
case TerrainType.PSYCHIC:
- return i18next.t("terrain:psychicClearMessage");
+ return "The weirdness disappeared from the battlefield!";
}
}
export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string {
if (terrainType === TerrainType.MISTY) {
- return i18next.t("terrain:mistyBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)});
+ return getPokemonMessage(pokemon, " surrounds itself with a protective mist!");
}
- return i18next.t("terrain:defaultBlockMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), terrainName: getTerrainName(terrainType)});
+ return getPokemonMessage(pokemon, ` is protected by the ${Utils.toReadableString(TerrainType[terrainType])} Terrain!`);
}
interface WeatherPoolEntry {
diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts
index 46faf1d1656b..5cdabfe78c23 100644
--- a/src/enums/battler-tag-type.ts
+++ b/src/enums/battler-tag-type.ts
@@ -59,9 +59,5 @@ export enum BattlerTagType {
MINIMIZED = "MINIMIZED",
DESTINY_BOND = "DESTINY_BOND",
CENTER_OF_ATTENTION = "CENTER_OF_ATTENTION",
- ICE_FACE = "ICE_FACE",
- RECEIVE_DOUBLE_DAMAGE = "TAKE_DOUBLE_DAMAGE",
- ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
- DISGUISE = "DISGUISE",
- MYSTERY_ENCOUNTER_POST_SUMMON = "MYSTERY_ENCOUNTER_POST_SUMMON" // Provides effects on post-summon for MEs
+ ICE_FACE = "ICE_FACE"
}
diff --git a/src/enums/game-data-type.ts b/src/enums/game-data-type.ts
index 179817fe5be6..d672253794a4 100644
--- a/src/enums/game-data-type.ts
+++ b/src/enums/game-data-type.ts
@@ -6,5 +6,6 @@ export enum GameDataType {
SESSION,
SETTINGS,
TUTORIALS,
- SEEN_DIALOGUES
+ SEEN_DIALOGUES,
+ RUN_HISTORY
}
diff --git a/src/enums/mystery-encounter-type.ts b/src/enums/mystery-encounter-type.ts
deleted file mode 100644
index a29a409103d1..000000000000
--- a/src/enums/mystery-encounter-type.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export enum MysteryEncounterType {
- MYSTERIOUS_CHALLENGERS,
- MYSTERIOUS_CHEST,
- DARK_DEAL,
- FIGHT_OR_FLIGHT,
- SLEEPING_SNORLAX,
- TRAINING_SESSION
-}
diff --git a/src/field/arena.ts b/src/field/arena.ts
index 269003b54c70..2d20abeedd17 100644
--- a/src/field/arena.ts
+++ b/src/field/arena.ts
@@ -73,21 +73,21 @@ export class Arena {
}
}
- randomSpecies(waveIndex: integer, level: integer, attempt?: integer, luckValue?: integer, isBoss?: boolean): PokemonSpecies {
+ randomSpecies(waveIndex: integer, level: integer, attempt?: integer, luckValue?: integer): PokemonSpecies {
const overrideSpecies = this.scene.gameMode.getOverrideSpecies(waveIndex);
if (overrideSpecies) {
return overrideSpecies;
}
- const isBossSpecies = !!this.scene.getEncounterBossSegments(waveIndex, level) && !!this.pokemonPool[BiomePoolTier.BOSS].length
+ const isBoss = !!this.scene.getEncounterBossSegments(waveIndex, level) && !!this.pokemonPool[BiomePoolTier.BOSS].length
&& (this.biomeType !== Biome.END || this.scene.gameMode.isClassic || this.scene.gameMode.isWaveFinal(waveIndex));
- const randVal = isBossSpecies ? 64 : 512;
+ const randVal = isBoss ? 64 : 512;
// luck influences encounter rarity
let luckModifier = 0;
if (typeof luckValue !== "undefined") {
- luckModifier = luckValue * (isBossSpecies ? 0.5 : 2);
+ luckModifier = luckValue * (isBoss ? 0.5 : 2);
}
const tierValue = Utils.randSeedInt(randVal - luckModifier);
- let tier = !isBossSpecies
+ let tier = !isBoss
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
console.log(BiomePoolTier[tier]);
@@ -154,12 +154,12 @@ export class Arena {
return ret;
}
- randomTrainerType(waveIndex: integer, isBoss: boolean = false): TrainerType {
- const isTrainerBoss = !!this.trainerPool[BiomePoolTier.BOSS].length
- && (this.scene.gameMode.isTrainerBoss(waveIndex, this.biomeType, this.scene.offsetGym) || isBoss);
+ randomTrainerType(waveIndex: integer): TrainerType {
+ const isBoss = !!this.trainerPool[BiomePoolTier.BOSS].length
+ && this.scene.gameMode.isTrainerBoss(waveIndex, this.biomeType, this.scene.offsetGym);
console.log(isBoss, this.trainerPool);
- const tierValue = Utils.randSeedInt(!isTrainerBoss ? 512 : 64);
- let tier = !isTrainerBoss
+ const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
+ let tier = !isBoss
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
console.log(BiomePoolTier[tier]);
diff --git a/src/field/mystery-encounter-intro.ts b/src/field/mystery-encounter-intro.ts
deleted file mode 100644
index 82e9bb49f890..000000000000
--- a/src/field/mystery-encounter-intro.ts
+++ /dev/null
@@ -1,311 +0,0 @@
-import { GameObjects } from "phaser";
-import BattleScene from "../battle-scene";
-import MysteryEncounter from "../data/mystery-encounter";
-
-export class MysteryEncounterSpriteConfig {
- spriteKey: string; // e.g. "ace_trainer_f"
- fileRoot: string; // "trainer" for trainer sprites, "pokemon" for pokemon, etc. Refer to /public/images directory for the folder name
- hasShadow?: boolean = false; // Spawns shadow underneath sprite
- disableAnimation?: boolean = false; // Animates frames or not
- repeat?: boolean = false; // Cycles animation
- tint?: number;
- x?: number; // X offset
- y?: number; // Y offset
- scale?: number;
- isItem?: boolean; // For item sprites, set to true
-}
-
-/**
- * When a mystery encounter spawns, there are visuals (mainly sprites) tied to the field for the new encounter to inform the player of the type of encounter
- * These slide in with the field as part of standard field change cycle, and will typically be hidden after the player has selected an option for the encounter
- * Note: intro visuals are not "Trainers" or any other specific game object, though they may contain trainer sprites
- */
-export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Container {
- public encounter: MysteryEncounter;
- public spriteConfigs: MysteryEncounterSpriteConfig[];
-
- constructor(scene: BattleScene, encounter: MysteryEncounter) {
- super(scene, -72, 76);
- this.encounter = encounter;
- // Shallow copy configs to allow visual config updates at runtime without dirtying master copy of Encounter
- this.spriteConfigs = encounter.spriteConfigs.map(config => {
- return {
- ...config
- };
- });
- if (!this.spriteConfigs) {
- return;
- }
-
- const getSprite = (spriteKey: string, hasShadow?: boolean) => {
- const ret = this.scene.addFieldSprite(0, 0, spriteKey);
- ret.setOrigin(0.5, 1);
- ret.setPipeline(this.scene.spritePipeline, {tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow});
- return ret;
- };
-
- const getItemSprite = (spriteKey: string) => {
- const icon = this.scene.add.sprite(-19, 2, "items", spriteKey);
- icon.setOrigin(0.5, 1);
- return icon;
- };
-
- // Depending on number of sprites added, should space them to be on the circular field sprite
- const minX = -40;
- const maxX = 40;
- const origin = 4;
- let n = 0;
- // Sprites with custom X or Y defined will not count for normal spacing requirements
- const spacingValue = Math.round((maxX - minX) / Math.max(this.spriteConfigs.filter(s => !s.x && !s.y).length, 1));
-
- this.spriteConfigs?.forEach((config) => {
- let sprite: GameObjects.Sprite;
- let tintSprite: GameObjects.Sprite;
- if (!config.isItem) {
- sprite = getSprite(config.spriteKey, config.hasShadow);
- tintSprite = getSprite(config.spriteKey);
- } else {
- sprite = getItemSprite(config.spriteKey);
- tintSprite = getItemSprite(config.spriteKey);
- }
-
- tintSprite.setVisible(false);
-
- if (config.scale) {
- sprite.setScale(config.scale);
- tintSprite.setScale(config.scale);
- }
-
- // Sprite offset from origin
- if (config.x || config.y) {
- if (config.x) {
- sprite.x = origin + config.x;
- tintSprite.x = origin + config.x;
- }
- if (config.y) {
- sprite.y = origin + config.y;
- tintSprite.y = origin + config.y;
- }
- } else {
- // Single sprite
- if (this.spriteConfigs.length === 1) {
- sprite.x = origin;
- tintSprite.x = origin;
- } else {
- // Do standard sprite spacing (not including offset sprites)
- sprite.x = minX + (n + 0.5) * spacingValue + origin;
- tintSprite.x = minX + (n + 0.5) * spacingValue + origin;
- n++;
- }
- }
-
- this.add(sprite);
- this.add(tintSprite);
- });
- }
-
- loadAssets(): Promise {
- return new Promise(resolve => {
- if (!this.spriteConfigs) {
- resolve();
- }
-
- this.spriteConfigs.forEach((config) => {
- if (!config.isItem) {
- this.scene.loadAtlas(config.spriteKey, config.fileRoot);
- } else {
- this.scene.loadAtlas("items", "");
- }
- });
-
- this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
- this.spriteConfigs.every((config) => {
- if (config.isItem) {
- return true;
- }
-
- const originalWarn = console.warn;
-
- // Ignore warnings for missing frames, because there will be a lot
- console.warn = () => {
- };
- const frameNames = this.scene.anims.generateFrameNames(config.spriteKey, { zeroPad: 4, suffix: ".png", start: 1, end: 128 });
-
- console.warn = originalWarn;
- if (!(this.scene.anims.exists(config.spriteKey))) {
- this.scene.anims.create({
- key: config.spriteKey,
- frames: frameNames,
- frameRate: 12,
- repeat: -1
- });
- }
-
- return true;
- });
-
- resolve();
- });
-
- if (!this.scene.load.isLoading()) {
- this.scene.load.start();
- }
- });
- }
-
- initSprite(): void {
- if (!this.spriteConfigs) {
- return;
- }
-
- this.getSprites().map((sprite, i) => {
- if (!this.spriteConfigs[i].isItem) {
- sprite.setTexture(this.spriteConfigs[i].spriteKey).setFrame(0);
- }
- });
- this.getTintSprites().map((tintSprite, i) => {
- if (!this.spriteConfigs[i].isItem) {
- tintSprite.setTexture(this.spriteConfigs[i].spriteKey).setFrame(0);
- }
- });
-
- this.spriteConfigs.every((config, i) => {
- if (!config.tint) {
- return true;
- }
-
- const tintSprite = this.getAt(i * 2 + 1);
- this.tint(tintSprite, 0, config.tint);
-
- return true;
- });
- }
-
- /**
- * Attempts to animate a given set of {@linkcode Phaser.GameObjects.Sprite}
- * @see {@linkcode Phaser.GameObjects.Sprite.play}
- * @param sprite {@linkcode Phaser.GameObjects.Sprite} to animate
- * @param tintSprite {@linkcode Phaser.GameObjects.Sprite} placed on top of the sprite to add a color tint
- * @param animConfig {@linkcode Phaser.Types.Animations.PlayAnimationConfig} to pass to {@linkcode Phaser.GameObjects.Sprite.play}
- * @returns true if the sprite was able to be animated
- */
- tryPlaySprite(sprite: Phaser.GameObjects.Sprite, tintSprite: Phaser.GameObjects.Sprite, animConfig: Phaser.Types.Animations.PlayAnimationConfig): boolean {
- // Show an error in the console if there isn't a texture loaded
- if (sprite.texture.key === "__MISSING") {
- console.error(`No texture found for '${animConfig.key}'!`);
-
- return false;
- }
- // Don't try to play an animation when there isn't one
- if (sprite.texture.frameTotal <= 1) {
- console.warn(`No animation found for '${animConfig.key}'. Is this intentional?`);
-
- return false;
- }
-
- sprite.play(animConfig);
- tintSprite.play(animConfig);
-
- return true;
- }
-
- playAnim(): void {
- if (!this.spriteConfigs) {
- return;
- }
-
- const sprites = this.getSprites();
- const tintSprites = this.getTintSprites();
- this.spriteConfigs.forEach((config, i) => {
- if (!config.disableAnimation) {
- const trainerAnimConfig = {
- key: config.spriteKey,
- repeat: config?.repeat ? -1 : 0,
- startFrame: 0
- };
-
- this.tryPlaySprite(sprites[i], tintSprites[i], trainerAnimConfig);
- }
- });
- }
-
- getSprites(): Phaser.GameObjects.Sprite[] {
- if (!this.spriteConfigs) {
- return;
- }
-
- const ret: Phaser.GameObjects.Sprite[] = [];
- this.spriteConfigs.forEach((config, i) => {
- ret.push(this.getAt(i * 2));
- });
- return ret;
- }
-
- getTintSprites(): Phaser.GameObjects.Sprite[] {
- if (!this.spriteConfigs) {
- return;
- }
-
- const ret: Phaser.GameObjects.Sprite[] = [];
- this.spriteConfigs.forEach((config, i) => {
- ret.push(this.getAt(i * 2 + 1));
- });
-
- return ret;
- }
-
- tint(sprite, color: number, alpha?: number, duration?: integer, ease?: string): void {
- // const tintSprites = this.getTintSprites();
- sprite.setTintFill(color);
- sprite.setVisible(true);
-
- if (duration) {
- sprite.setAlpha(0);
-
- this.scene.tweens.add({
- targets: sprite,
- alpha: alpha || 1,
- duration: duration,
- ease: ease || "Linear"
- });
- } else {
- sprite.setAlpha(alpha);
- }
- }
-
- tintAll(color: number, alpha?: number, duration?: integer, ease?: string): void {
- const tintSprites = this.getTintSprites();
- tintSprites.map(tintSprite => {
- this.tint(tintSprite, color, alpha, duration, ease);
- });
- }
-
- untint(sprite, duration: integer, ease?: string): void {
- if (duration) {
- this.scene.tweens.add({
- targets: sprite,
- alpha: 0,
- duration: duration,
- ease: ease || "Linear",
- onComplete: () => {
- sprite.setVisible(false);
- sprite.setAlpha(1);
- }
- });
- } else {
- sprite.setVisible(false);
- sprite.setAlpha(1);
- }
- }
-
- untintAll(duration: integer, ease?: string): void {
- const tintSprites = this.getTintSprites();
- tintSprites.map(tintSprite => {
- this.untint(tintSprite, duration, ease);
- });
- }
-}
-
-export default interface MysteryEncounterIntroVisuals {
- scene: BattleScene
-}
diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts
index 9fd67a66896e..0fb74d51304c 100644
--- a/src/field/pokemon.ts
+++ b/src/field/pokemon.ts
@@ -23,7 +23,7 @@ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HelpingHandTag
import { WeatherType } from "../data/weather";
import { TempBattleStat } from "../data/temp-battle-stat";
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from "../data/arena-tag";
-import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AllyMoveCategoryPowerBoostAbAttr, FieldMoveTypePowerBoostAbAttr, AddSecondStrikeAbAttr, UserFieldMoveTypePowerBoostAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr } from "../data/ability";
+import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AllyMoveCategoryPowerBoostAbAttr, FieldMoveTypePowerBoostAbAttr, AddSecondStrikeAbAttr, UserFieldMoveTypePowerBoostAbAttr } from "../data/ability";
import PokemonData from "../system/pokemon-data";
import { BattlerIndex } from "../battle";
import { Mode } from "../ui/ui";
@@ -1733,15 +1733,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return (this.isPlayer() ? this.scene.getPlayerField() : this.scene.getEnemyField())[this.getFieldIndex() ? 0 : 1];
}
- /**
- * Gets the Pokémon on the allied field.
- *
- * @returns An array of Pokémon on the allied field.
- */
- getAlliedField(): Pokemon[] {
- return this instanceof PlayerPokemon ? this.scene.getPlayerField() : this.scene.getEnemyField();
- }
-
apply(source: Pokemon, move: Move): HitResult {
let result: HitResult;
const damage = new Utils.NumberHolder(0);
@@ -1844,10 +1835,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (source.getTag(HelpingHandTag)) {
power.value *= 1.5;
}
- const glaiveRushModifier = new Utils.IntegerHolder(1);
- if (this.getTag(BattlerTagType.RECEIVE_DOUBLE_DAMAGE)) {
- glaiveRushModifier.value = 2;
- }
let isCritical: boolean;
const critOnly = new Utils.BooleanHolder(false);
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
@@ -1917,7 +1904,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, numTargets, new Utils.IntegerHolder(0), twoStrikeMultiplier);
if (!isTypeImmune) {
- damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier.value * screenMultiplier.value * twoStrikeMultiplier.value * glaiveRushModifier.value * criticalMultiplier.value * ((this.scene.randBattleSeedInt(15) + 85) / 100));
+ damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier.value * screenMultiplier.value * twoStrikeMultiplier.value * ((this.scene.randBattleSeedInt(15) + 85) / 100) * criticalMultiplier.value);
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) {
if (!move.hasAttr(BypassBurnDamageReductionAttr)) {
const burnDamageReductionCancelled = new Utils.BooleanHolder(false);
@@ -2001,13 +1988,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
/**
- * We explicitly require to ignore the faint phase here, as we want to show the messages
- * about the critical hit and the super effective/not very effective messages before the faint phase.
- */
+ * We explicitly require to ignore the faint phase here, as we want to show the messages
+ * about the critical hit and the super effective/not very effective messages before the faint phase.
+ */
damage.value = this.damageAndUpdate(damage.value, result as DamageResult, isCritical, oneHitKo, oneHitKo, true);
this.turnData.damageTaken += damage.value;
-
- // queue critical message before effectiveness
if (isCritical) {
this.scene.queueMessage(i18next.t("battle:hitResultCriticalHit"));
}
@@ -2020,7 +2005,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
source.turnData.damageDealt += damage.value;
source.turnData.currDamageDealt = damage.value;
this.battleData.hitCount++;
- // create attack result and push to turnData
const attackResult = { move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id };
this.turnData.attacksReceived.unshift(attackResult);
if (source.isPlayer() && !this.isPlayer()) {
@@ -2028,8 +2012,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
- // want to include is.Fainted() in case multi hit move ends early, still want to render message
- if (source.turnData.hitsLeft === 1 || this.isFainted()) {
+ if (source.turnData.hitsLeft === 1) {
switch (result) {
case HitResult.SUPER_EFFECTIVE:
this.scene.queueMessage(i18next.t("battle:hitResultSuperEffective"));
@@ -2050,13 +2033,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (this.isFainted()) {
- // set splice index here, so future scene queues happen before FaintedPhase
- this.scene.setPhaseQueueSplice();
this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), oneHitKo));
this.resetSummonData();
}
if (damage) {
+ this.scene.clearPhaseQueueSplice();
+
const attacker = this.scene.getPokemonById(source.id);
destinyTag?.lapse(attacker, BattlerTagLapseType.CUSTOM);
}
@@ -2080,14 +2063,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return result;
}
- /**
- * called by damageAndUpdate()
- * @param damage integer
- * @param ignoreSegments boolean, not currently used
- * @param preventEndure used to update damage if endure or sturdy
- * @param ignoreFaintPhase flag on wheter to add FaintPhase if pokemon after applying damage faints
- * @returns integer representing damage
- */
damage(damage: integer, ignoreSegments: boolean = false, preventEndure: boolean = false, ignoreFaintPhase: boolean = false): integer {
if (this.isFainted()) {
return 0;
@@ -2109,16 +2084,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
damage = Math.min(damage, this.hp);
+
this.hp = this.hp - damage;
if (this.isFainted() && !ignoreFaintPhase) {
- /**
- * when adding the FaintPhase, want to toggle future unshiftPhase() and queueMessage() calls
- * to appear before the FaintPhase (as FaintPhase will potentially end the encounter and add Phases such as
- * GameOverPhase, VictoryPhase, etc.. that will interfere with anything else that happens during this MoveEffectPhase)
- *
- * once the MoveEffectPhase is over (and calls it's .end() function, shiftPhase() will reset the PhaseQueueSplice via clearPhaseQueueSplice() )
- */
- this.scene.setPhaseQueueSplice();
this.scene.unshiftPhase(new FaintPhase(this.scene, this.getBattlerIndex(), preventEndure));
this.resetSummonData();
}
@@ -2126,16 +2094,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return damage;
}
- /**
- * Called by apply(), given the damage, adds a new DamagePhase and actually updates HP values, etc.
- * @param damage integer - passed to damage()
- * @param result an enum if it's super effective, not very, etc.
- * @param critical boolean if move is a critical hit
- * @param ignoreSegments boolean, passed to damage() and not used currently
- * @param preventEndure boolean, ignore endure properties of pokemon, passed to damage()
- * @param ignoreFaintPhase boolean to ignore adding a FaintPhase, passsed to damage()
- * @returns integer of damage done
- */
damageAndUpdate(damage: integer, result?: DamageResult, critical: boolean = false, ignoreSegments: boolean = false, preventEndure: boolean = false, ignoreFaintPhase: boolean = false): integer {
const damagePhase = new DamagePhase(this.scene, this.getBattlerIndex(), damage, result as DamageResult, critical);
this.scene.unshiftPhase(damagePhase);
@@ -2170,9 +2128,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const newTag = getBattlerTag(tagType, turnCount, sourceMove, sourceId);
const cancelled = new Utils.BooleanHolder(false);
- applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, newTag, cancelled);
-
- this.getAlliedField().forEach(p => applyPreApplyBattlerTagAbAttrs(UserFieldBattlerTagImmunityAbAttr, p, newTag, cancelled));
+ applyPreApplyBattlerTagAbAttrs(PreApplyBattlerTagAbAttr, this, newTag, cancelled);
if (!cancelled.value && newTag.canAdd(this)) {
this.summonData.tags.push(newTag);
@@ -2586,8 +2542,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const cancelled = new Utils.BooleanHolder(false);
applyPreSetStatusAbAttrs(StatusEffectImmunityAbAttr, this, effect, cancelled, quiet);
- this.getAlliedField().forEach(pokemon => applyPreSetStatusAbAttrs(UserFieldStatusEffectImmunityAbAttr, pokemon, effect, cancelled, quiet));
-
if (cancelled.value) {
return false;
}
@@ -3959,7 +3913,6 @@ export class PokemonSummonData {
public moveset: PokemonMove[];
// If not initialized this value will not be populated from save data.
public types: Type[] = null;
- public mysteryEncounterBattleEffects: (pokemon: Pokemon) => void = null;
}
export class PokemonBattleData {
diff --git a/src/field/trainer.ts b/src/field/trainer.ts
index d43a2025723e..3e78afeae831 100644
--- a/src/field/trainer.ts
+++ b/src/field/trainer.ts
@@ -35,16 +35,11 @@ export default class Trainer extends Phaser.GameObjects.Container {
public name: string;
public partnerName: string;
- constructor(scene: BattleScene, trainerType: TrainerType, variant: TrainerVariant, partyTemplateIndex?: integer, name?: string, partnerName?: string, trainerConfigOverride?: TrainerConfig) {
+ constructor(scene: BattleScene, trainerType: TrainerType, variant: TrainerVariant, partyTemplateIndex?: integer, name?: string, partnerName?: string) {
super(scene, -72, 80);
this.config = trainerConfigs.hasOwnProperty(trainerType)
? trainerConfigs[trainerType]
: trainerConfigs[TrainerType.ACE_TRAINER];
-
- if (trainerConfigOverride) {
- this.config = trainerConfigOverride;
- }
-
this.variant = variant;
this.partyTemplateIndex = Math.min(partyTemplateIndex !== undefined ? partyTemplateIndex : Utils.randSeedWeightedItem(this.config.partyTemplates.map((_, i) => i)),
this.config.partyTemplates.length - 1);
diff --git a/src/form-change-phase.ts b/src/form-change-phase.ts
index 62331ec13897..ebf91c635fd7 100644
--- a/src/form-change-phase.ts
+++ b/src/form-change-phase.ts
@@ -8,9 +8,8 @@ import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon";
import { Mode } from "./ui/ui";
import PartyUiHandler from "./ui/party-ui-handler";
import { BattleSpec } from "#enums/battle-spec";
-import { MovePhase, PokemonHealPhase } from "./phases";
+import { BattlePhase, MovePhase, PokemonHealPhase } from "./phases";
import { getTypeRgb } from "./data/type";
-import {BattlePhase} from "#app/phases/battle-phase";
export class FormChangePhase extends EvolutionPhase {
private formChange: SpeciesFormChange;
diff --git a/src/game-mode.ts b/src/game-mode.ts
index 3e8c832c544b..0a472e223e30 100644
--- a/src/game-mode.ts
+++ b/src/game-mode.ts
@@ -28,7 +28,6 @@ interface GameModeConfig {
hasRandomBosses?: boolean;
isSplicedOnly?: boolean;
isChallenge?: boolean;
- hasMysteryEncounters?: boolean;
}
export class GameMode implements GameModeConfig {
@@ -45,7 +44,6 @@ export class GameMode implements GameModeConfig {
public isChallenge: boolean;
public challenges: Challenge[];
public battleConfig: FixedBattleConfigs;
- public hasMysteryEncounters: boolean;
constructor(modeId: GameModes, config: GameModeConfig, battleConfig?: FixedBattleConfigs) {
this.modeId = modeId;
@@ -303,7 +301,7 @@ export class GameMode implements GameModeConfig {
export function getGameMode(gameMode: GameModes): GameMode {
switch (gameMode) {
case GameModes.CLASSIC:
- return new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true, hasMysteryEncounters: true }, classicFixedBattles);
+ return new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true }, classicFixedBattles);
case GameModes.ENDLESS:
return new GameMode(GameModes.ENDLESS, { isEndless: true, hasShortBiomes: true, hasRandomBosses: true });
case GameModes.SPLICED_ENDLESS:
@@ -311,6 +309,6 @@ export function getGameMode(gameMode: GameModes): GameMode {
case GameModes.DAILY:
return new GameMode(GameModes.DAILY, { isDaily: true, hasTrainers: true, hasNoShop: true });
case GameModes.CHALLENGE:
- return new GameMode(GameModes.CHALLENGE, { isClassic: true, hasTrainers: true, isChallenge: true, hasMysteryEncounters: true }, classicFixedBattles);
+ return new GameMode(GameModes.CHALLENGE, { isClassic: true, hasTrainers: true, isChallenge: true }, classicFixedBattles);
}
}
diff --git a/src/loading-scene.ts b/src/loading-scene.ts
index fdb9f5f6610d..15cd295d23c8 100644
--- a/src/loading-scene.ts
+++ b/src/loading-scene.ts
@@ -22,8 +22,6 @@ import { initStatsKeys } from "./ui/game-stats-ui-handler";
import { initVouchers } from "./system/voucher";
import { Biome } from "#enums/biome";
import { TrainerType } from "#enums/trainer-type";
-import {initMysteryEncounterDialogue} from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-import {initMysteryEncounters} from "#app/data/mystery-encounters/mystery-encounters";
export class LoadingScene extends SceneBase {
readonly LOAD_EVENTS = Phaser.Loader.Events;
@@ -346,8 +344,6 @@ export class LoadingScene extends SceneBase {
initMoves();
initAbilities();
initChallenges();
- initMysteryEncounterDialogue();
- initMysteryEncounters();
}
loadLoadingScreen() {
diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts
index 9c572302c095..4e69db202314 100644
--- a/src/locales/de/ability-trigger.ts
+++ b/src/locales/de/ability-trigger.ts
@@ -7,6 +7,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
"iceFaceAvoidedDamage": "{{pokemonName}} wehrt Schaden mit {{abilityName}} ab!",
"trace": "{{pokemonName}} kopiert {{abilityName}} von {{targetName}}!",
"windPowerCharged": "Der Treffer durch {{moveName}} läd die Stärke von {{pokemonName}} auf!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
"quickDraw": "Durch Schnellschuss kann {{pokemonName}} schneller handeln als sonst!",
} as const;
diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts
index d3da08445750..099020d46d56 100644
--- a/src/locales/de/battle.ts
+++ b/src/locales/de/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"regainHealth": "KP von {{pokemonName}} wurden wieder aufgefrischt!",
"stealEatBerry": "{{pokemonName}} stole and ate\n{{targetName}}'s {{berryName}}!",
"fainted": "{{pokemonNameWithAffix}} wurde besiegt!",
- "statsAnd": "und",
- "stats": "Werte",
"statRose": "{{stats}} von {{pokemonNameWithAffix}} steigt!",
"statSharplyRose": "{{stats}} von {{pokemonNameWithAffix}} steigt stark!",
"statRoseDrastically": "{{stats}} von {{pokemonNameWithAffix}} steigt drastisch!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{stats}} von {{pokemonNameWithAffix}} sinkt stark!",
"statSeverelyFell": "{{stats}} von {{pokemonNameWithAffix}} sinkt drastisch!",
"statWontGoAnyLower": "{{stats}} von {{pokemonNameWithAffix}} kann nicht weiter sinken!",
- "statRoseMultiple": "{{stats}} von {{pokemonNameWithAffix}} steigen!",
- "statSharplyRoseMultiple": "{{stats}} von {{pokemonNameWithAffix}} steigen stark!",
- "statRoseDrasticallyMultiple": "{{stats}} von {{pokemonNameWithAffix}} steigen drastisch!",
- "statWontGoAnyHigherMultiple": "{{stats}} von {{pokemonNameWithAffix}} können nicht weiter erhöht werden!",
- "statFellMultiple": "{{stats}} von {{pokemonNameWithAffix}} sinken!",
- "statHarshlyFellMultiple": "{{stats}} von {{pokemonNameWithAffix}} sinken stark!",
- "statSeverelyFellMultiple": "{{stats}} von {{pokemonNameWithAffix}} sinken drastisch!",
- "statWontGoAnyLowerMultiple": "{{stats}} von {{pokemonNameWithAffix}} können nicht weiter sinken!",
"ppReduced": "{{moveName}} von {{targetName}} wird um {{reduction}} AP reduziert!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} kann sich wegen des Rückstoßes durch den Angriff nicht bewegen!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} kann nicht mehr fliehen!",
diff --git a/src/locales/de/config.ts b/src/locales/de/config.ts
index 3c16f81270d8..92544d87ea3c 100644
--- a/src/locales/de/config.ts
+++ b/src/locales/de/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const deConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/de/run-history-ui-handler.ts b/src/locales/de/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/de/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts
index efd0420ff7e5..85f8645d69f9 100644
--- a/src/locales/de/settings.ts
+++ b/src/locales/de/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "Controller",
"gamepadSupport": "Controllerunterstützung",
"showBgmBar": "Musiknamen anzeigen",
- "shopOverlayOpacity": "Shop Overlay Opacity"
} as const;
diff --git a/src/locales/de/weather.ts b/src/locales/de/weather.ts
index 8a820f3d549c..305fd7e78270 100644
--- a/src/locales/de/weather.ts
+++ b/src/locales/de/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "Rätselhafte Luftströmungen haben den Angriff abgeschwächt!",
"strongWindsClearMessage": "Die rätselhafte Luftströmung hat sich wieder geleget.",
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "Nebelfeld",
- "mistyStartMessage": "Am Boden breitet sich dichter Nebel aus!",
- "mistyClearMessage": "Das Nebelfeld ist wieder verschwunden!",
- "mistyBlockMessage": "{{pokemonNameWithAffix}} wird vom Nebelfeld geschützt!",
-
- "electric": "Elektrofeld",
- "electricStartMessage": "Elektrische Energie fließt durch den Boden!",
- "electricClearMessage": "Das Elektrofeld ist wieder verschwunden!",
-
- "grassy": "Grasfeld",
- "grassyStartMessage": "Dichtes Gras schießt aus dem Boden!",
- "grassyClearMessage": "Das Grasfeld ist wieder verschwunden!",
-
- "psychic": "Psychofeld",
- "psychicStartMessage": "Der Boden fühlt sich seltsam an!",
- "psychicClearMessage": "Das Psychofeld ist wieder verschwunden!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}} wird vom {{terrainName}} geschützt!"
-};
diff --git a/src/locales/en/ability-trigger.ts b/src/locales/en/ability-trigger.ts
index df4589695150..b516bc8dde03 100644
--- a/src/locales/en/ability-trigger.ts
+++ b/src/locales/en/ability-trigger.ts
@@ -10,5 +10,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
"quickDraw": "{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts
index 55afe22450e8..a42743ef2541 100644
--- a/src/locales/en/battle.ts
+++ b/src/locales/en/battle.ts
@@ -48,7 +48,6 @@ export const battle: SimpleTranslationEntries = {
"noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!",
"noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!",
"noPokeballStrong": "The target Pokémon is too strong to be caught!\nYou need to weaken it first!",
- "noPokeballMysteryEncounter": "You aren't able to\ncatch this Pokémon!",
"noEscapeForce": "An unseen force\nprevents escape.",
"noEscapeTrainer": "You can't run\nfrom a trainer battle!",
"noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nprevents {{escapeVerb}}!",
@@ -69,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"regainHealth": "{{pokemonName}} regained\nhealth!",
"stealEatBerry": "{{pokemonName}} stole and ate\n{{targetName}}'s {{berryName}}!",
"fainted": "{{pokemonNameWithAffix}} fainted!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
"statSharplyRose": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
"statRoseDrastically": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
@@ -79,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
"statSeverelyFell": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
"statWontGoAnyLower": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!",
@@ -144,6 +133,5 @@ export const battle: SimpleTranslationEntries = {
"battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} is being salt cured!",
"battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
"battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
- "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!",
- "mysteryEncounterAppeared": "What's this?"
+ "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!"
} as const;
diff --git a/src/locales/en/config.ts b/src/locales/en/config.ts
index c47c7f4cdc26..19daabb6144a 100644
--- a/src/locales/en/config.ts
+++ b/src/locales/en/config.ts
@@ -29,7 +29,6 @@ import { menu } from "./menu";
import { menuUiHandler } from "./menu-ui-handler";
import { modifierType } from "./modifier-type";
import { move } from "./move";
-import { mysteryEncounter } from "./mystery-encounter";
import { nature } from "./nature";
import { partyUiHandler } from "./party-ui-handler";
import { pokeball } from "./pokeball";
@@ -43,8 +42,9 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { modifierSelectUiHandler } from "./modifier-select-ui-handler";
+import { runHistory } from "./run-history-ui-handler";
export const enConfig = {
ability: ability,
@@ -76,8 +76,8 @@ export const enConfig = {
menuUiHandler: menuUiHandler,
modifierType: modifierType,
move: move,
- mysteryEncounter: mysteryEncounter,
nature: nature,
+ partyUiHandler: partyUiHandler,
pokeball: pokeball,
pokemon: pokemon,
pokemonInfo: pokemonInfo,
@@ -87,13 +87,12 @@ export const enConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
tutorial: tutorial,
voucher: voucher,
weather: weather,
- partyUiHandler: partyUiHandler,
- modifierSelectUiHandler: modifierSelectUiHandler
+ modifierSelectUiHandler: modifierSelectUiHandler,
+ runHistory: runHistory,
};
diff --git a/src/locales/en/menu-ui-handler.ts b/src/locales/en/menu-ui-handler.ts
index 97d6e38a0998..b784593d742c 100644
--- a/src/locales/en/menu-ui-handler.ts
+++ b/src/locales/en/menu-ui-handler.ts
@@ -3,6 +3,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
export const menuUiHandler: SimpleTranslationEntries = {
"GAME_SETTINGS": "Game Settings",
"ACHIEVEMENTS": "Achievements",
+ "RUN_HISTORY": "Run History",
"STATS": "Stats",
"VOUCHERS": "Vouchers",
"EGG_LIST": "Egg List",
diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts
index f466b73c7590..09d9baea6fb2 100644
--- a/src/locales/en/modifier-type.ts
+++ b/src/locales/en/modifier-type.ts
@@ -152,7 +152,6 @@ export const modifierType: ModifierTypeTranslationEntries = {
"SACRED_ASH": { name: "Sacred Ash" },
"REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting." },
- "WHITE_HERB": { name: "White Herb", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." },
"ETHER": { name: "Ether" },
"MAX_ETHER": { name: "Max Ether" },
diff --git a/src/locales/en/mystery-encounter.ts b/src/locales/en/mystery-encounter.ts
deleted file mode 100644
index b928fa38f54a..000000000000
--- a/src/locales/en/mystery-encounter.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import {SimpleTranslationEntries} from "#app/interfaces/locales";
-
-export const mysteryEncounter: SimpleTranslationEntries = {
-
- // Mysterious Encounters -- Common Tier
-
- "mysterious_chest_intro_message": "You found...@d{32} a chest?",
- "mysterious_chest_title": "The Mysterious Chest",
- "mysterious_chest_description": "A beautifully ornamented chest stands on the ground. There must be something good inside... right?",
- "mysterious_chest_query": "Will you open it?",
- "mysterious_chest_option_1_label": "Open it",
- "mysterious_chest_option_1_tooltip": "(35%) Something terrible\n(40%) Okay Rewards\n(20%) Good Rewards\n(4%) Great Rewards\n(1%) Amazing Rewards",
- "mysterious_chest_option_2_label": "It's too risky, leave",
- "mysterious_chest_option_2_tooltip": "(-) No Rewards",
- "mysterious_chest_option_1_selected_message": "You open the chest to find...",
- "mysterious_chest_option_2_selected_message": "You hurry along your way,\nwith a slight feeling of regret.",
- "mysterious_chest_option_1_normal_result": "Just some normal tools and items.",
- "mysterious_chest_option_1_good_result": "Some pretty nice tools and items.",
- "mysterious_chest_option_1_great_result": "A couple great tools and items!",
- "mysterious_chest_option_1_amazing_result": "Whoa! An amazing item!",
- "mysterious_chest_option_1_bad_result": `Oh no!@d{32}\nThe chest was trapped!
- $Your @ec{pokeName} jumps in front of you\nbut is KOed in the process.`,
-
- "fight_or_flight_intro_message": "Something shiny is sparkling\non the ground near that Pokémon!",
- "fight_or_flight_title": "Fight or Flight",
- "fight_or_flight_description": "It looks like there's a strong Pokémon guarding an item. Battling is the straightforward approach, but this Pokémon looks strong. You could also try to sneak around, though the Pokémon might catch you.",
- "fight_or_flight_query": "What will you do?",
- "fight_or_flight_option_1_label": "Battle it",
- "fight_or_flight_option_1_tooltip": "(+) Hard Battle\n(+) New Item",
- "fight_or_flight_option_2_label": "Sneak around",
- "fight_or_flight_option_2_tooltip": "(35%) Steal Item\n(65%) Harder Battle",
- "fight_or_flight_option_3_label": "Leave",
- "fight_or_flight_option_3_tooltip": "(-) No Rewards",
- "fight_or_flight_option_1_selected_message": "You approach the\nPokémon without fear.",
- "fight_or_flight_option_2_good_result": `.@d{32}.@d{32}.@d{32}
- $You manage to sneak your way\npast and grab the item!`,
- "fight_or_flight_option_2_bad_result": `.@d{32}.@d{32}.@d{32}
- $The Pokémon catches you\nas you try to sneak around!`,
- "fight_or_flight_boss_enraged": "The opposing @ec{enemyPokemon} has become enraged!",
- "fight_or_flight_option_3_selected": "You leave the strong Pokémon\nwith its prize and continue on.",
-
- // Mysterious Encounters -- Uncommon Tier
-
- "mysterious_challengers_intro_message": "Mysterious challengers have appeared!",
- "mysterious_challengers_title": "Mysterious Challengers",
- "mysterious_challengers_description": "If you defeat a challenger, you might impress them enough to receive a boon. But some look tough, are you up to the challenge?",
- "mysterious_challengers_query": "Who will you battle?",
- "mysterious_challengers_option_1_label": "A clever, mindful foe",
- "mysterious_challengers_option_1_tooltip": "(+) Standard Battle\n(+) Move Item Rewards",
- "mysterious_challengers_option_2_label": "A strong foe",
- "mysterious_challengers_option_2_tooltip": "(+) Hard Battle\n(+) Good Rewards",
- "mysterious_challengers_option_3_label": "The mightiest foe",
- "mysterious_challengers_option_3_tooltip": "(+) Brutal Battle\n(+) Great Rewards",
- "mysterious_challengers_option_selected_message": "The trainer steps forward...",
- "mysterious_challengers_outro_win": "The mysterious challenger was defeated!",
-
- // Mysterious Encounters -- Rare Tier
- "training_session_intro_message": "You've come across some\ntraining tools and supplies.",
- "training_session_title": "Training Session",
- "training_session_description": "These supplies look like they could be used to train a member of your party! There are a few ways you could train your Pokémon, by battling against it with the rest of your team.",
- "training_session_query": "How should you train?",
- "training_session_option_1_label": "Light Training",
- "training_session_option_1_tooltip": "(-) Light Battle\n(+) Improve 2 Random IVs of Pokémon",
- "training_session_option_2_label": "Moderate Training",
- "training_session_option_2_tooltip": "(-) Moderate Battle\n(+) Change Pokémon's Nature",
- "training_session_option_2_select_prompt": "Select a new nature\nto train your Pokémon in.",
- "training_session_option_3_label": "Heavy Training",
- "training_session_option_3_tooltip": "(-) Harsh Battle\n(+) Change Pokémon's Ability",
- "training_session_option_3_select_prompt": "Select a new ability\nto train your Pokémon in.",
- "training_session_option_selected_message": "@ec{selectedPokemon} moves across\nthe clearing to face you...",
- "training_session_battle_finished_1": `@ec{selectedPokemon} returns, feeling\nworn out but accomplished!
- $Its @ec{stat1} and @ec{stat2} IVs were improved!`,
- "training_session_battle_finished_2": `@ec{selectedPokemon} returns, feeling\nworn out but accomplished!
- $Its nature was changed to @ec{nature}!`,
- "training_session_battle_finished_3": `@ec{selectedPokemon} returns, feeling\nworn out but accomplished!
- $Its ability was changed to @ec{ability}!`,
- "training_session_outro_win": "That was a successful training session!",
-
- // Mysterious Encounters -- Super Rare Tier
-
- "dark_deal_intro_message": "A strange man in a tattered coat\nstands in your way...",
- "dark_deal_speaker": "Shady Guy",
- "dark_deal_intro_dialogue": `Hey, you!
- $I've been working on a new device\nto bring out a Pokémon's latent power!
- $It completely rebinds the Pokémon's atoms\nat a molecular level into a far more powerful form.
- $Hehe...@d{64} I just need some sac-@d{32}\nErr, test subjects, to prove it works.`,
- "dark_deal_title": "Dark Deal",
- "dark_deal_description": "The disturbing fellow holds up some Pokéballs.\n\"I'll make it worth your while! You can have these strong Pokéballs as payment, All I need is a Pokémon from your team! Hehe...\"",
- "dark_deal_query": "What will you do?",
- "dark_deal_option_1_label": "Accept", // Give player 10 rogue balls. Remove a random Pokémon from player's party. Fight a legendary Pokémon as a boss
- "dark_deal_option_1_tooltip": "(+) 5 Rogue Balls\n(?) Enhance a Random Pokémon", // Give player 10 rogue balls. Remove a random Pokémon from player's party. Fight a legendary Pokémon as a boss
- "dark_deal_option_2_label": "Refuse",
- "dark_deal_option_2_tooltip": "(-) No Rewards",
- "dark_deal_option_1_selected": `Let's see, that @ec{pokeName} will do nicely!
- $Remember, I'm not responsible\nif anything bad happens!@d{32} Hehe...`,
- "dark_deal_option_1_selected_message": `The man hands you 5 Rogue Balls.
- $@ec{pokeName} hops into the strange machine...
- $Flashing lights and weird noises\nstart coming from the machine!
- $...@d{96} Something emerges\nfrom the device, raging wildly!`,
- "dark_deal_option_2_selected": "Not gonna help a poor fellow out?\nPah!",
- "dark_deal_outro": "After the harrowing encounter,\nyou collect yourself and depart.",
-
- "sleeping_snorlax_intro_message": `As you walk down a narrow pathway, you see a towering silhouette blocking your path.
- $You get closer to see a Snorlax sleeping peacefully.\nIt seems like there's no way around it.`,
- "sleeping_snorlax_title": "Sleeping Snorlax",
- "sleeping_snorlax_description": "You could attack it to try and get it to move, or simply wait for it to wake up.",
- "sleeping_snorlax_query": "What will you do?",
- "sleeping_snorlax_option_1_label": "Fight it",
- "sleeping_snorlax_option_1_tooltip": "(+) Fight Sleeping Snorlax",
- "sleeping_snorlax_option_2_label": "Wait for it to move",
- "sleeping_snorlax_option_2_tooltip": "(75%) Wait a short time\n(25%) Wait a long time",
- "sleeping_snorlax_option_3_label": "Steal",
- "sleeping_snorlax_option_3_tooltip": "(+) Leftovers",
- "sleeping_snorlax_option_3_disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
- "sleeping_snorlax_option_1_selected_message": "You approach the\nPokémon without fear.",
- "sleeping_snorlax_option_2_selected_message": `.@d{32}.@d{32}.@d{32}
- $You wait for a time, but the Snorlax's yawns make your party sleepy.`,
- "sleeping_snorlax_option_2_good_result": "When you all awaken, the Snorlax is no where to be found - but your Pokémon are all healed!",
- "sleeping_snorlax_option_2_bad_result": `Your @ec{primaryName} is still asleep...
- $But on the bright side, the Snorlax left something behind...
- $@s{item_fanfare}You gained a Berry!`,
- "sleeping_snorlax_option_3_good_result": "Your @ec{option3PrimaryName} uses @ec{option3PrimaryMove}! @s{item_fanfare}It steals Leftovers off the sleeping Snorlax and you make out like bandits!",
- // "sleeping_snorlax_outro_win": "The mysterious challengers were defeated!",
-
-} as const;
diff --git a/src/locales/en/party-ui-handler.ts b/src/locales/en/party-ui-handler.ts
index 37343cfa8920..78fdcc14dbe9 100644
--- a/src/locales/en/party-ui-handler.ts
+++ b/src/locales/en/party-ui-handler.ts
@@ -16,7 +16,6 @@ export const partyUiHandler: SimpleTranslationEntries = {
"PASS_BATON": "Pass Baton",
"UNPAUSE_EVOLUTION": "Unpause Evolution",
"REVIVE": "Revive",
- "SELECT": "Select",
"choosePokemon": "Choose a Pokémon.",
"doWhatWithThisPokemon": "Do what with this Pokémon?",
diff --git a/src/locales/en/pokemon-info.ts b/src/locales/en/pokemon-info.ts
index 70a06294c761..f31fdac69ab5 100644
--- a/src/locales/en/pokemon-info.ts
+++ b/src/locales/en/pokemon-info.ts
@@ -15,8 +15,7 @@ export const pokemonInfo: PokemonInfoTranslationEntries = {
"SPD": "Speed",
"SPDshortened": "Spd",
"ACC": "Accuracy",
- "EVA": "Evasiveness",
- "HPStat": "HP"
+ "EVA": "Evasiveness"
},
Type: {
diff --git a/src/locales/en/run-history-ui-handler.ts b/src/locales/en/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/en/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts
index 0b88f5e82c8e..f68a649269f7 100644
--- a/src/locales/en/settings.ts
+++ b/src/locales/en/settings.ts
@@ -15,7 +15,6 @@ export const settings: SimpleTranslationEntries = {
"skipSeenDialogues": "Skip Seen Dialogues",
"battleStyle": "Battle Style",
"enableRetries": "Enable Retries",
- "hideIvs": "Hide IV scanner",
"tutorials": "Tutorials",
"touchControls": "Touch Controls",
"vibrations": "Vibrations",
@@ -97,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "Controller",
"gamepadSupport": "Gamepad Support",
"showBgmBar": "Show Music Names",
- "shopOverlayOpacity": "Shop Overlay Opacity"
} as const;
diff --git a/src/locales/en/starter-select-ui-handler.ts b/src/locales/en/starter-select-ui-handler.ts
index 6d7b7f7cfb20..ac59785bab72 100644
--- a/src/locales/en/starter-select-ui-handler.ts
+++ b/src/locales/en/starter-select-ui-handler.ts
@@ -6,8 +6,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales";
* account interactions, descriptive text, etc.
*/
export const starterSelectUiHandler: SimpleTranslationEntries = {
- "confirmStartTeam": "Begin with these Pokémon?",
- "invalidParty": "This is not a valid starting party!",
+ "confirmStartTeam":"Begin with these Pokémon?",
"gen1": "I",
"gen2": "II",
"gen3": "III",
@@ -23,7 +22,6 @@ export const starterSelectUiHandler: SimpleTranslationEntries = {
"nature": "Nature:",
"eggMoves": "Egg Moves",
"addToParty": "Add to Party",
- "removeFromParty": "Remove from Party",
"toggleIVs": "Toggle IVs",
"manageMoves": "Manage Moves",
"manageNature": "Manage Nature",
diff --git a/src/locales/en/weather.ts b/src/locales/en/weather.ts
index 96985ca25fb0..c7b2963ccd81 100644
--- a/src/locales/en/weather.ts
+++ b/src/locales/en/weather.ts
@@ -43,17 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "The heavy wind stopped."
};
-
-export const terrain: SimpleTranslationEntries = {
- "mistyStartMessage": "Mist swirled around the battlefield!",
- "mistyClearMessage": "The mist disappeared from the battlefield.",
-
- "electricStartMessage": "An electric current ran across the battlefield!",
- "electricClearMessage": "The electricity disappeared from the battlefield.",
-
- "grassyStartMessage": "Grass grew to cover the battlefield!",
- "grassyClearMessage": "The grass disappeared from the battlefield.",
-
- "psychicStartMessage": "The battlefield got weird!",
- "psychicClearMessage": "The weirdness disappeared from the battlefield!",
-};
diff --git a/src/locales/es/ability-trigger.ts b/src/locales/es/ability-trigger.ts
index fe0d9aadc7fe..5c09c3832c04 100644
--- a/src/locales/es/ability-trigger.ts
+++ b/src/locales/es/ability-trigger.ts
@@ -8,5 +8,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
"windPowerCharged": "¡{{pokemonName}} se ha cargado de electricidad gracias a {{moveName}}!",
"quickDraw": "{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts
index c5dbb79c307b..ddba5fab9a83 100644
--- a/src/locales/es/battle.ts
+++ b/src/locales/es/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"regainHealth": "¡{{pokemonName}} recuperó\nPS!",
"stealEatBerry": "¡{{pokemonName}} robó la {{berryName}}\nde {{targetName}} y se la comió!",
"fainted": "¡{{pokemonNameWithAffix}} se debilitó!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "¡El {{stats}} de {{pokemonNameWithAffix}} ha subido!",
"statSharplyRose": "¡El {{stats}} de {{pokemonNameWithAffix}} ha subido mucho!",
"statRoseDrastically": "¡El {{stats}} de {{pokemonNameWithAffix}} ha subido muchísimo!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "¡El {{stats}} de {{pokemonNameWithAffix}}} ha bajado mucho!",
"statSeverelyFell": "¡El {{stats}} de {{pokemonNameWithAffix}} ha bajado muchísimo!",
"statWontGoAnyLower": "¡El {{stats}} de {{pokemonNameWithAffix}} no puede bajar más!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!",
diff --git a/src/locales/es/config.ts b/src/locales/es/config.ts
index c37f96a2aa5d..bedd53dcc293 100644
--- a/src/locales/es/config.ts
+++ b/src/locales/es/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const esConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/es/run-history-ui-handler.ts b/src/locales/es/run-history-ui-handler.ts
new file mode 100644
index 000000000000..9b666a2e1a4e
--- /dev/null
+++ b/src/locales/es/run-history-ui-handler.ts
@@ -0,0 +1,30 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts
index 407bfab602f7..dfd6f0972424 100644
--- a/src/locales/es/settings.ts
+++ b/src/locales/es/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "Controller",
"gamepadSupport": "Gamepad Support",
"showBgmBar": "Show Music Names",
- "shopOverlayOpacity": "Opacidad de la fase de compra"
} as const;
diff --git a/src/locales/es/weather.ts b/src/locales/es/weather.ts
index 1129443d71bd..37f574878dc0 100644
--- a/src/locales/es/weather.ts
+++ b/src/locales/es/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "¡Las misteriosas turbulencias atenúan el ataque!",
"strongWindsClearMessage": "El fuerte viento cesó."
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "Misty",
- "mistyStartMessage": "Mist swirled around the battlefield!",
- "mistyClearMessage": "The mist disappeared from the battlefield.",
- "mistyBlockMessage": "{{pokemonNameWithAffix}} surrounds itself with a protective mist!",
-
- "electric": "Electric",
- "electricStartMessage": "An electric current ran across the battlefield!",
- "electricClearMessage": "The electricity disappeared from the battlefield.",
-
- "grassy": "Grassy",
- "grassyStartMessage": "Grass grew to cover the battlefield!",
- "grassyClearMessage": "The grass disappeared from the battlefield.",
-
- "psychic": "Psychic",
- "psychicStartMessage": "The battlefield got weird!",
- "psychicClearMessage": "The weirdness disappeared from the battlefield!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}} is protected by the {{terrainName}} Terrain!"
-};
diff --git a/src/locales/fr/ability-trigger.ts b/src/locales/fr/ability-trigger.ts
index e595a501cb62..f99ff15c26fb 100644
--- a/src/locales/fr/ability-trigger.ts
+++ b/src/locales/fr/ability-trigger.ts
@@ -10,5 +10,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copie le talent {{abilityName}}\nde {{targetName}} !",
"windPowerCharged": "{{pokemonName}} a été touché par la capacité {{moveName}} et se charge en électricité !",
"quickDraw": "{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts
index c8baecc84c3e..5bcf0763ef0c 100644
--- a/src/locales/fr/battle.ts
+++ b/src/locales/fr/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "L’énergie de {{pokemonName}}\nest drainée !",
"regainHealth": "{{pokemonName}} récupère\ndes PV !",
"fainted": "{{pokemonNameWithAffix}}\nest K.O. !",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{stats}} de {{pokemonNameWithAffix}}\naugmente !",
"statSharplyRose": "{{stats}} de {{pokemonNameWithAffix}}\naugmente beaucoup !",
"statRoseDrastically": "{{stats}} de {{pokemonNameWithAffix}}\naugmente énormément !",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{stats}} de {{pokemonNameWithAffix}}\nbaisse beaucoup !",
"statSeverelyFell": "{{stats}} de {{pokemonNameWithAffix}}\nbaisse énormément !",
"statWontGoAnyLower": "{{stats}} de {{pokemonNameWithAffix}}\nne peut plus baisser !",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "Les PP de la capacité {{moveName}}\nde {{targetName}} baissent de {{reduction}} !",
"battlerTagsRechargingLapse": "Le contrecoup empêche {{pokemonNameWithAffix}}\n de bouger !",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}\nne peut plus s’échapper !",
diff --git a/src/locales/fr/config.ts b/src/locales/fr/config.ts
index af18aab34005..55eae8c1dd5f 100644
--- a/src/locales/fr/config.ts
+++ b/src/locales/fr/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const frConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/fr/run-history-ui-handler.ts b/src/locales/fr/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/fr/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts
index 9e3bd04923ad..cd85b0f8cb9e 100644
--- a/src/locales/fr/settings.ts
+++ b/src/locales/fr/settings.ts
@@ -95,6 +95,5 @@ export const settings: SimpleTranslationEntries = {
"mute": "Muet",
"controller": "Controller",
"gamepadSupport": "Gamepad Support",
- "showBgmBar": "Titre de la musique",
- "shopOverlayOpacity": "Opacité boutique"
+ "showBgmBar": "Montrer titre de la musique",
} as const;
diff --git a/src/locales/fr/weather.ts b/src/locales/fr/weather.ts
index 3427748480e5..3df8d0e20c9d 100644
--- a/src/locales/fr/weather.ts
+++ b/src/locales/fr/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "Le courant aérien mystérieux affaiblit l’attaque !",
"strongWindsClearMessage": "Le vent mystérieux s’est dissipé…"
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "Brumeux",
- "mistyStartMessage": "La brume recouvre le terrain !",
- "mistyClearMessage": "La brume qui recouvrait le terrain se dissipe…",
- "mistyBlockMessage": "La brume enveloppe {{pokemonNameWithAffix}} !",
-
- "electric": "Électrifié",
- "electricStartMessage": "De l’électricité parcourt le terrain !",
- "electricClearMessage": "L’électricité parcourant le terrain s’est dissipée…",
-
- "grassy": "Herbu",
- "grassyStartMessage": "Un beau gazon pousse sur le terrain !",
- "grassyClearMessage": "Le gazon disparait…",
-
- "psychic": "Psychique",
- "psychicStartMessage": "Le sol se met à réagir de façon bizarre…",
- "psychicClearMessage": "Le sol redevient normal !",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}} est protégé\npar le Champ {{terrainName}} !"
-};
diff --git a/src/locales/it/ability-trigger.ts b/src/locales/it/ability-trigger.ts
index 46839a32778f..1f6fcfb12580 100644
--- a/src/locales/it/ability-trigger.ts
+++ b/src/locales/it/ability-trigger.ts
@@ -8,5 +8,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
"windPowerCharged": "Venire colpito da {{moveName}} ha caricato {{pokemonName}}!",
"quickDraw":"{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts
index e0407de6ad02..f44ca8e493c5 100644
--- a/src/locales/it/battle.ts
+++ b/src/locales/it/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "Viene prelevata energia\n da{{pokemonName}}!",
"regainHealth": "{{pokemonName}} ha rigenerato\npunti salute!",
"fainted": "{{pokemonNameWithAffix}} non è più in\ngrado di combattere!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a!",
"statSharplyRose": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a molto!",
"statRoseDrastically": "{{pokemonNameWithAffix}}'s {{stats}} è aumentato/a drasticamente!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a molto!",
"statSeverelyFell": "{{pokemonNameWithAffix}}'s {{stats}} è diminuito/a drasticamente!",
"statWontGoAnyLower": "{{pokemonNameWithAffix}}'s {{stats}} non può diminuire più di così!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} deve\nricaricarsi!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} non può\npiù fuggire!",
diff --git a/src/locales/it/config.ts b/src/locales/it/config.ts
index ac77e8146239..9175d40b97f7 100644
--- a/src/locales/it/config.ts
+++ b/src/locales/it/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const itConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/it/run-history-ui-handler.ts b/src/locales/it/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/it/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/it/settings.ts b/src/locales/it/settings.ts
index 07cbe6b7f46a..af48368aeebd 100644
--- a/src/locales/it/settings.ts
+++ b/src/locales/it/settings.ts
@@ -3,7 +3,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales.js";
export const settings: SimpleTranslationEntries = {
"boy": "Ragazzo",
"girl": "Ragazza",
- "general": "Generale",
+ "general": "General",
"display": "Display",
"audio": "Audio",
"gamepad": "Gamepad",
@@ -94,7 +94,6 @@ export const settings: SimpleTranslationEntries = {
"alt": " (Alt)",
"mute": "Mute",
"controller": "Controller",
- "gamepadSupport": "Supporto Gamepad",
- "showBgmBar": "Mostra Nomi Musica",
- "shopOverlayOpacity": "Opacità Finestra Negozio"
+ "gamepadSupport": "Gamepad Support",
+ "showBgmBar": "Show Music Names",
} as const;
diff --git a/src/locales/it/weather.ts b/src/locales/it/weather.ts
index 604108435c3e..f5d8e3b9397f 100644
--- a/src/locales/it/weather.ts
+++ b/src/locales/it/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "La corrente misteriosa indebolisce l’attacco!",
"strongWindsClearMessage": "La corrente d'aria è cessata."
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "Misty",
- "mistyStartMessage": "Mist swirled around the battlefield!",
- "mistyClearMessage": "The mist disappeared from the battlefield.",
- "mistyBlockMessage": "{{pokemonNameWithAffix}} surrounds itself with a protective mist!",
-
- "electric": "Electric",
- "electricStartMessage": "An electric current ran across the battlefield!",
- "electricClearMessage": "The electricity disappeared from the battlefield.",
-
- "grassy": "Grassy",
- "grassyStartMessage": "Grass grew to cover the battlefield!",
- "grassyClearMessage": "The grass disappeared from the battlefield.",
-
- "psychic": "Psychic",
- "psychicStartMessage": "The battlefield got weird!",
- "psychicClearMessage": "The weirdness disappeared from the battlefield!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}} is protected by the {{terrainName}} Terrain!"
-};
diff --git a/src/locales/ko/ability-trigger.ts b/src/locales/ko/ability-trigger.ts
index e49dafe6bb82..58ba7bf9aa6e 100644
--- a/src/locales/ko/ability-trigger.ts
+++ b/src/locales/ko/ability-trigger.ts
@@ -10,5 +10,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
"windPowerCharged": "{{pokemonName}}[[는]]\n{{moveName}}에 맞아 충전되었다!",
"quickDraw": "{{pokemonName}}[[는]]\n퀵드로에 의해 행동이 빨라졌다!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/ko/battle.ts b/src/locales/ko/battle.ts
index 02693cb5f1ac..25ff106946b9 100644
--- a/src/locales/ko/battle.ts
+++ b/src/locales/ko/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"stealEatBerry": "{{pokemonName}}[[가]]\n{{targetName}}의 {{berryName}}[[를]] 빼앗아 먹었다!",
"regainHealth": "{{pokemonName}}[[는]]\n체력을 회복했다!",
"fainted": "{{pokemonNameWithAffix}}[[는]] 쓰러졌다!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{pokemonNameWithAffix}}의\n{{stats}}[[가]] 올라갔다!",
"statSharplyRose": "{{pokemonNameWithAffix}}의\n{{stats}}[[가]] 크게 올라갔다!",
"statRoseDrastically": "{{pokemonNameWithAffix}}의\n{{stats}}[[가]] 매우 크게 올라갔다!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{pokemonNameWithAffix}}의\n{{stats}}[[가]] 크게 떨어졌다!",
"statSeverelyFell": "{{pokemonNameWithAffix}}의\n{{stats}}[[가]] 매우 크게 떨어졌다!",
"statWontGoAnyLower": "{{pokemonNameWithAffix}}의\n{{stats}}[[는]] 더 떨어지지 않는다!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "{{targetName}}의\n{{moveName}}[[를]] {{reduction}} 깎았다!",
"battlerTagsRechargingLapse": "공격의 반동으로\n{{pokemonNameWithAffix}}[[는]] 움직일 수 없다!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}[[는]]\n이제 도망칠 수 없다!",
diff --git a/src/locales/ko/config.ts b/src/locales/ko/config.ts
index fa81dee55abf..dc64e12356ad 100644
--- a/src/locales/ko/config.ts
+++ b/src/locales/ko/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const koConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/ko/run-history-ui-handler.ts b/src/locales/ko/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/ko/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/ko/settings.ts b/src/locales/ko/settings.ts
index e1ee3b4e01c4..ef1469fc8cbc 100644
--- a/src/locales/ko/settings.ts
+++ b/src/locales/ko/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "컨트롤러",
"gamepadSupport": "게임패드 지원",
"showBgmBar": "BGM 제목 보여주기",
- "shopOverlayOpacity": "상점 오버레이 투명도"
} as const;
diff --git a/src/locales/ko/weather.ts b/src/locales/ko/weather.ts
index c89cc335859a..9aca57c49d2e 100644
--- a/src/locales/ko/weather.ts
+++ b/src/locales/ko/weather.ts
@@ -44,24 +44,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "수수께끼의 난기류가 공격을 약하게 만들었다!",
"strongWindsClearMessage": "수수께끼의 난기류가 멈췄다!" // 임의번역
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "미스트필드",
- "mistyStartMessage": "발밑이 안개로 자욱해졌다!",
- "mistyClearMessage": "발밑의 안개가 사라졌다!",
- "mistyBlockMessage": "{{pokemonNameWithAffix}}[[를]]\n미스트필드가 지켜주고 있다!",
-
- "electric": "일렉트릭필드",
- "electricStartMessage": "발밑에 전기가 흐르기 시작했다!",
- "electricClearMessage": "발밑의 전기가 사라졌다!",
-
- "grassy": "그래스필드",
- "grassyStartMessage": "발밑에 풀이 무성해졌다!",
- "grassyClearMessage": "발밑의 풀이 사라졌다!",
-
- "psychic": "사이코필드",
- "psychicStartMessage": "발밑에서 이상한 느낌이 든다!",
- "psychicClearMessage": "발밑의 이상한 느낌이 사라졌다!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}}[[를]]\n{{terrainName}}[[가]] 지켜주고 있다!"
-};
diff --git a/src/locales/pt_BR/ability-trigger.ts b/src/locales/pt_BR/ability-trigger.ts
index eb7e6e615cb6..526c6def80d6 100644
--- a/src/locales/pt_BR/ability-trigger.ts
+++ b/src/locales/pt_BR/ability-trigger.ts
@@ -9,6 +9,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
"poisonHeal": "{{abilityName}} de {{pokemonName}}\nrestaurou seus PS um pouco!",
"trace": "{{pokemonName}} copiou {{abilityName}}\nde {{targetName}}!",
"windPowerCharged": "Ser atingido por {{moveName}} carregou {{pokemonName}} com poder!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
"quickDraw":"{{pokemonName}} pode agir mais rápido que o normal\ngraças ao seu Quick Draw!",
} as const;
diff --git a/src/locales/pt_BR/battle.ts b/src/locales/pt_BR/battle.ts
index 97746674a3e2..b63a03b25cf4 100644
--- a/src/locales/pt_BR/battle.ts
+++ b/src/locales/pt_BR/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"regainHealth": "{{pokemonName}} recuperou\npontos de saúde!",
"stealEatBerry": "{{pokemonName}} stole and ate\n{{targetName}}'s {{berryName}}!",
"fainted": "{{pokemonNameWithAffix}} desmaiou!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{stats}} de {{pokemonNameWithAffix}} aumentou!",
"statSharplyRose": "{{stats}} de {{pokemonNameWithAffix}} aumentou bruscamente!",
"statRoseDrastically": "{{stats}} de {{pokemonNameWithAffix}} aumentou drasticamente!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{stats}} de {{pokemonNameWithAffix}} diminuiu duramente!",
"statSeverelyFell": "{{stats}} de {{pokemonNameWithAffix}} diminuiu severamente!",
"statWontGoAnyLower": "{{stats}} de {{pokemonNameWithAffix}} não vai mais diminuir!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "O PP do movimento {{moveName}} de\n{{targetName}} foi reduzido em {{reduction}}!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} precisa\nrecarregar!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} não pode\nmais escapar!",
diff --git a/src/locales/pt_BR/config.ts b/src/locales/pt_BR/config.ts
index 4b3649f96ada..5a571815c972 100644
--- a/src/locales/pt_BR/config.ts
+++ b/src/locales/pt_BR/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -76,13 +76,13 @@ export const ptBrConfig = {
modifierType: modifierType,
move: move,
nature: nature,
+ partyUiHandler: partyUiHandler,
pokeball: pokeball,
pokemon: pokemon,
pokemonInfo: pokemonInfo,
pokemonInfoContainer: pokemonInfoContainer,
saveSlotSelectUiHandler: saveSlotSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
settings: settings,
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
@@ -92,6 +92,5 @@ export const ptBrConfig = {
tutorial: tutorial,
voucher: voucher,
weather: weather,
- partyUiHandler: partyUiHandler,
modifierSelectUiHandler: modifierSelectUiHandler
};
diff --git a/src/locales/pt_BR/run-history-ui-handler.ts b/src/locales/pt_BR/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/pt_BR/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/pt_BR/settings.ts b/src/locales/pt_BR/settings.ts
index b6a48143435d..9d336cf07574 100644
--- a/src/locales/pt_BR/settings.ts
+++ b/src/locales/pt_BR/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "Controle",
"gamepadSupport": "Suporte para Controle",
"showBgmBar": "Show Music Names",
- "shopOverlayOpacity": "Opacidade da Loja"
} as const;
diff --git a/src/locales/pt_BR/weather.ts b/src/locales/pt_BR/weather.ts
index 31e35657c7f3..0787b32e4162 100644
--- a/src/locales/pt_BR/weather.ts
+++ b/src/locales/pt_BR/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "Os ventos fortes diminuíram.",
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "Enevoado",
- "mistyStartMessage": "Uma névoa se espalhou pelo campo de batalha!",
- "mistyClearMessage": "A névou sumiu do campo de batalha.",
- "mistyBlockMessage": "{{pokemonNameWithAffix}} se envolveu com uma névoa protetora!",
-
- "electric": "Elétrico",
- "electricStartMessage": "Uma corrente elétrica se espalhou pelo campo de batalha!",
- "electricClearMessage": "A eletricidade sumiu do campo de batalha.",
-
- "grassy": "de Plantas",
- "grassyStartMessage": "Grama cresceu para cobrir o campo de batalha!",
- "grassyClearMessage": "A grama sumiu do campo de batalha.",
-
- "psychic": "Psíquico",
- "psychicStartMessage": "O campo de batalha ficou esquisito!",
- "psychicClearMessage": "A esquisitice sumiu do campo de batalha",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}} está protegido pelo Terreno {{terrainName}}!"
-};
diff --git a/src/locales/zh_CN/ability-trigger.ts b/src/locales/zh_CN/ability-trigger.ts
index 9f02975afadf..a9d7fa5b2023 100644
--- a/src/locales/zh_CN/ability-trigger.ts
+++ b/src/locales/zh_CN/ability-trigger.ts
@@ -8,5 +8,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}}复制了{{targetName}}的\n{{abilityName}}!",
"windPowerCharged": "受{{moveName}}的影响,{{pokemonName}}提升了能力!",
"quickDraw":"因为速击效果发动,\n{{pokemonName}}比平常出招更快了!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/zh_CN/battle.ts b/src/locales/zh_CN/battle.ts
index 2e7fd23eac84..d8388064bd74 100644
--- a/src/locales/zh_CN/battle.ts
+++ b/src/locales/zh_CN/battle.ts
@@ -68,8 +68,6 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "{{pokemonName}}\n吸取了体力!",
"regainHealth": "{{pokemonName}}\n回复了体力!",
"fainted": "{{pokemonNameWithAffix}}\n倒下了!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{pokemonNameWithAffix}}\n的{{stats}}提高了!",
"statSharplyRose": "{{pokemonNameWithAffix}}\n的{{stats}}大幅提高了!",
"statRoseDrastically": "{{pokemonNameWithAffix}}\n的{{stats}}极大幅提高了!",
@@ -78,14 +76,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{pokemonNameWithAffix}}\n的{{stats}}大幅降低了!",
"statSeverelyFell": "{{pokemonNameWithAffix}}\n的{{stats}}极大幅降低了!",
"statWontGoAnyLower": "{{pokemonNameWithAffix}}\n的{{stats}}已经无法再降低了!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "降低了{{targetName}}的\n{{moveName}}的PP{{reduction}}点!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}\n因攻击的反作用力而无法动弹!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}不能逃跑!",
diff --git a/src/locales/zh_CN/config.ts b/src/locales/zh_CN/config.ts
index b55b2aa865c1..8f654b56d9ab 100644
--- a/src/locales/zh_CN/config.ts
+++ b/src/locales/zh_CN/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const zhCnConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/zh_CN/run-history-ui-handler.ts b/src/locales/zh_CN/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/zh_CN/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/zh_CN/settings.ts b/src/locales/zh_CN/settings.ts
index 92372deec422..3ca6cb435c6b 100644
--- a/src/locales/zh_CN/settings.ts
+++ b/src/locales/zh_CN/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "控制器",
"gamepadSupport": "手柄支持",
"showBgmBar": "显示音乐名称",
- "shopOverlayOpacity": "商店显示不透明度"
} as const;
diff --git a/src/locales/zh_CN/weather.ts b/src/locales/zh_CN/weather.ts
index ea4deffbd559..d280dfccb95f 100644
--- a/src/locales/zh_CN/weather.ts
+++ b/src/locales/zh_CN/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "神秘的乱流停止了。"
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "薄雾",
- "mistyStartMessage": "脚下雾气缭绕!",
- "mistyClearMessage": "脚下的雾气消失不见了!",
- "mistyBlockMessage": "{{pokemonNameWithAffix}}正受到薄雾场地的保护!",
-
- "electric": "电气",
- "electricStartMessage": "脚下电光飞闪!",
- "electricClearMessage": "脚下的电光消失不见了!",
-
- "grassy": "青草",
- "grassyStartMessage": "脚下青草如茵!",
- "grassyClearMessage": "脚下的青草消失不见了!",
-
- "psychic": "精神",
- "psychicStartMessage": "脚下传来了奇妙的感觉!",
- "psychicClearMessage": "脚下的奇妙感觉消失了!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}}正受到{{terrainName}}的的保护!"
-};
diff --git a/src/locales/zh_TW/ability-trigger.ts b/src/locales/zh_TW/ability-trigger.ts
index 888212c306f8..c436e5021f7b 100644
--- a/src/locales/zh_TW/ability-trigger.ts
+++ b/src/locales/zh_TW/ability-trigger.ts
@@ -8,5 +8,4 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} 複製了 {{targetName}} 的\n{{abilityName}}!",
"windPowerCharged": "受 {{moveName}} 的影響, {{pokemonName}} 提升了能力!",
"quickDraw":"{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
- "disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
diff --git a/src/locales/zh_TW/battle.ts b/src/locales/zh_TW/battle.ts
index a39218e9c913..bfd3885ca313 100644
--- a/src/locales/zh_TW/battle.ts
+++ b/src/locales/zh_TW/battle.ts
@@ -65,8 +65,6 @@ export const battle: SimpleTranslationEntries = {
"drainMessage": "{{pokemonName}} 吸取了體力!",
"regainHealth": "{{pokemonName}} 回復了體力!",
"fainted": "{{pokemonNameWithAffix}} 倒下了!",
- "statsAnd": "and",
- "stats": "Stats",
"statRose": "{{pokemonNameWithAffix}} 的 {{stats}} 提高了!",
"statSharplyRose": "{{pokemonNameWithAffix}} 的 {{stats}} 大幅提高了!",
"statRoseDrastically": "{{pokemonNameWithAffix}} 的 {{stats}} 極大幅提高了!",
@@ -75,14 +73,6 @@ export const battle: SimpleTranslationEntries = {
"statHarshlyFell": "{{pokemonNameWithAffix}} 的 {{stats}} 大幅降低了!",
"statSeverelyFell": "{{pokemonNameWithAffix}} 的 {{stats}} 極大幅降低了!",
"statWontGoAnyLower": "{{pokemonNameWithAffix}} 的 {{stats}} 已經無法再降低了!",
- "statRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose!",
- "statSharplyRoseMultiple": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!",
- "statRoseDrasticallyMultiple": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!",
- "statWontGoAnyHigherMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!",
- "statFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} fell!",
- "statHarshlyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!",
- "statSeverelyFellMultiple": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!",
- "statWontGoAnyLowerMultiple": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!",
"ppReduced": "降低了 {{targetName}} 的\n{{moveName}} 的PP{{reduction}}點!",
"battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}因攻擊的反作用力而無法動彈!",
"battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}不能逃跑!",
diff --git a/src/locales/zh_TW/config.ts b/src/locales/zh_TW/config.ts
index 6886a750d62a..e4dfafdd43ed 100644
--- a/src/locales/zh_TW/config.ts
+++ b/src/locales/zh_TW/config.ts
@@ -39,7 +39,7 @@ import { statusEffect } from "./status-effect";
import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { voucher } from "./voucher";
-import { terrain, weather } from "./weather";
+import { weather } from "./weather";
import { partyUiHandler } from "./party-ui-handler";
import { settings } from "./settings.js";
import { common } from "./common.js";
@@ -85,7 +85,6 @@ export const zhTwConfig = {
splashMessages: splashMessages,
starterSelectUiHandler: starterSelectUiHandler,
statusEffect: statusEffect,
- terrain: terrain,
titles: titles,
trainerClasses: trainerClasses,
trainerNames: trainerNames,
diff --git a/src/locales/zh_TW/run-history-ui-handler.ts b/src/locales/zh_TW/run-history-ui-handler.ts
new file mode 100644
index 000000000000..d0f622599e2f
--- /dev/null
+++ b/src/locales/zh_TW/run-history-ui-handler.ts
@@ -0,0 +1,31 @@
+import { SimpleTranslationEntries } from "#app/interfaces/locales";
+
+export const runHistory: SimpleTranslationEntries = {
+ "victory": "Victory!",
+ "defeatedWild": "Defeated by ",
+ "defeatedTrainer": "Defeated by ",
+ "defeatedTrainerDouble": "Defeated by Duo",
+ "defeatedRival": "Defeated by Rival",
+ "defeated":"Defeated",
+ "luck":"Luck",
+ "score":"Score",
+ "mode":"Mode",
+ "challengeRules":"Rule(s)",
+ "challengeMonoGen1":"Gen I",
+ "challengeMonoGen2":"Gen II",
+ "challengeMonoGen3":"Gen III",
+ "challengeMonoGen4":"Gen IV",
+ "challengeMonoGen5":"Gen V",
+ "challengeMonoGen6":"Gen VI",
+ "challengeMonoGen7":"Gen VII",
+ "challengeMonoGen8":"Gen VIII",
+ "challengeMonoGen9":"Gen IX",
+ "playerItems":"Player Items",
+ "personalBest":"Personal Best!",
+ "SPDshortened":"Vel.",
+ "runInfo":"Run Info",
+ "money":"Money",
+} as const;
+
+//Mode Information found in game-mode.ts
+//Wave / Lv found in save-slot-select-ui-handler.ts
diff --git a/src/locales/zh_TW/settings.ts b/src/locales/zh_TW/settings.ts
index c6c055ed4d2d..dcb87fafe35c 100644
--- a/src/locales/zh_TW/settings.ts
+++ b/src/locales/zh_TW/settings.ts
@@ -96,5 +96,4 @@ export const settings: SimpleTranslationEntries = {
"controller": "控制器",
"gamepadSupport": "手柄支持",
"showBgmBar": "Show Music Names",
- "shopOverlayOpacity": "Shop Overlay Opacity"
} as const;
diff --git a/src/locales/zh_TW/weather.ts b/src/locales/zh_TW/weather.ts
index bfc5e0998dcb..ae0646ce33df 100644
--- a/src/locales/zh_TW/weather.ts
+++ b/src/locales/zh_TW/weather.ts
@@ -43,24 +43,3 @@ export const weather: SimpleTranslationEntries = {
"strongWindsEffectMessage": "The mysterious air current weakened the attack!",
"strongWindsClearMessage": "神秘的亂流停止了。"
};
-
-export const terrain: SimpleTranslationEntries = {
- "misty": "薄霧",
- "mistyStartMessage": "腳下霧氣繚繞!",
- "mistyClearMessage": "腳下的霧氣消失不見了!",
- "mistyBlockMessage": "{{pokemonNameWithAffix}}正受到薄霧場地的保護!",
-
- "electric": "電氣",
- "electricStartMessage": "腳下電流飛閃!",
- "electricClearMessage": "腳下的電流消失了!",
-
- "grassy": "青草",
- "grassyStartMessage": "腳下青草如茵!",
- "grassyClearMessage": "腳下的青草消失不見了!",
-
- "psychic": "精神",
- "psychicStartMessage": "腳下傳來了奇妙的感覺!",
- "psychicClearMessage": "腳下的奇妙感覺消失了!",
-
- "defaultBlockMessage": "{{pokemonNameWithAffix}}正受到{{terrainName}}的保護!"
-};
diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts
index 10acd57779cb..d8ec0072bd4c 100644
--- a/src/modifier/modifier-type.ts
+++ b/src/modifier/modifier-type.ts
@@ -1,5 +1,5 @@
import * as Modifiers from "./modifier";
-import { AttackMove, allMoves, selfStatLowerMoves } from "../data/move";
+import { AttackMove, allMoves } from "../data/move";
import { MAX_PER_TYPE_POKEBALLS, PokeballType, getPokeballCatchMultiplier, getPokeballName } from "../data/pokeball";
import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon";
import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions";
@@ -143,7 +143,7 @@ export interface GeneratedPersistentModifierType {
getPregenArgs(): any[];
}
-export class AddPokeballModifierType extends ModifierType {
+class AddPokeballModifierType extends ModifierType {
private pokeballType: PokeballType;
private count: integer;
@@ -1188,7 +1188,6 @@ export const modifierTypes = {
SACRED_ASH: () => new AllPokemonFullReviveModifierType("modifierType:ModifierType.SACRED_ASH", "sacred_ash"),
REVIVER_SEED: () => new PokemonHeldItemModifierType("modifierType:ModifierType.REVIVER_SEED", "reviver_seed", (type, args) => new Modifiers.PokemonInstantReviveModifier(type, (args[0] as Pokemon).id)),
- WHITE_HERB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.WHITE_HERB", "white_herb", (type, args) => new Modifiers.PokemonResetNegativeStatStageModifier(type, (args[0] as Pokemon).id)),
ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.ETHER", "ether", 10),
MAX_ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.MAX_ETHER", "max_ether", -1),
@@ -1491,14 +1490,6 @@ const modifierPool: ModifierPool = {
// If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear
return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => checkedMoves.includes(m.moveId)))) ? 10 : 0;
}, 10),
- new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => {
- const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT];
- const weightMultiplier = party.filter(
- p => !p.getHeldItems().some(i => i instanceof Modifiers.PokemonResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) &&
- (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => selfStatLowerMoves.includes(m.moveId)))).length;
- // If a party member has one of the above moves or abilities and doesn't have max herbs, the herb will appear more frequently
- return 3*(weightMultiplier? 2: 1)+(weightMultiplier? weightMultiplier-1: 0);
- }, 10),
new WeightedModifierType(modifierTypes.REVIVER_SEED, 4),
new WeightedModifierType(modifierTypes.CANDY_JAR, 5),
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 9),
@@ -1564,7 +1555,6 @@ const wildModifierPool: ModifierPool = {
}),
[ModifierTier.ULTRA]: [
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),
- new WeightedModifierType(modifierTypes.WHITE_HERB, 2)
].map(m => {
m.setTier(ModifierTier.ULTRA); return m;
}),
@@ -1593,8 +1583,7 @@ const trainerModifierPool: ModifierPool = {
m.setTier(ModifierTier.GREAT); return m;
}),
[ModifierTier.ULTRA]: [
- new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 5),
- new WeightedModifierType(modifierTypes.WHITE_HERB, 1),
+ new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 1),
].map(m => {
m.setTier(ModifierTier.ULTRA); return m;
}),
@@ -1812,74 +1801,21 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
}
}
-export interface CustomModifierSettings {
- guaranteedModifierTiers?: ModifierTier[];
- guaranteedModifierTypeOptions?: ModifierTypeOption[];
- guaranteedModifierTypeFuncs?: ModifierTypeFunc[];
- fillRemaining?: boolean;
- rerollMultiplier?: number;
-}
-
export function getModifierTypeFuncById(id: string): ModifierTypeFunc {
return modifierTypes[id];
}
-export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemon[], modifierTiers?: ModifierTier[], customModifierSettings?: CustomModifierSettings): ModifierTypeOption[] {
+export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemon[], modifierTiers?: ModifierTier[]): ModifierTypeOption[] {
const options: ModifierTypeOption[] = [];
const retryCount = Math.min(count * 5, 50);
- if (!customModifierSettings) {
- new Array(count).fill(0).map((_, i) => {
- options.push(getModifierTypeOptionWithRetry(options, retryCount, party, modifierTiers?.length > i ? modifierTiers[i] : undefined));
- });
- } else {
- // Guaranteed mods first
- if (customModifierSettings?.guaranteedModifierTypeOptions?.length) {
- customModifierSettings?.guaranteedModifierTypeOptions.forEach((option) => {
- options.push(option);
- });
- }
-
- // Guaranteed mod funcs second
- if (customModifierSettings?.guaranteedModifierTypeFuncs?.length) {
- customModifierSettings?.guaranteedModifierTypeFuncs.forEach((mod, i) => {
- const modifierId = Object.keys(modifierTypes).find(k => modifierTypes[k] === mod);
- let guaranteedMod: ModifierType = modifierTypes[modifierId]?.();
-
- // Gets tier of item by checking player item pool
- Object.keys(modifierPool).every(modifierTier => {
- const modType = modifierPool[modifierTier].find(m => {
- if (m.modifierType.id === modifierId) {
- return m;
- }
- });
- if (modType) {
- guaranteedMod = modType.modifierType;
- return false;
- }
- return true;
- });
-
- const modType = guaranteedMod instanceof ModifierTypeGenerator ? guaranteedMod.generateType(party) : guaranteedMod;
- const option = new ModifierTypeOption(modType, 0);
- options.push(option);
- });
+ new Array(count).fill(0).map((_, i) => {
+ let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers?.length > i ? modifierTiers[i] : undefined);
+ let r = 0;
+ while (options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) {
+ candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount);
}
-
- // Guaranteed tiers third
- if (customModifierSettings?.guaranteedModifierTiers?.length) {
- customModifierSettings?.guaranteedModifierTiers.forEach((tier) => {
- options.push(getModifierTypeOptionWithRetry(options, retryCount, party, tier));
- });
- }
-
- // Fill remaining
- if (options.length < count && customModifierSettings.fillRemaining) {
- while (options.length < count) {
- options.push(getModifierTypeOptionWithRetry(options, retryCount, party, undefined));
- }
- }
- }
-
+ options.push(candidate);
+ });
// OVERRIDE IF NECESSARY
if (Overrides.ITEM_REWARD_OVERRIDE?.length) {
options.forEach((mod, i) => {
@@ -1891,15 +1827,6 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo
return options;
}
-function getModifierTypeOptionWithRetry(existingOptions: ModifierTypeOption[], retryCount: integer, party: PlayerPokemon[], tier?: ModifierTier): ModifierTypeOption {
- let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, tier);
- let r = 0;
- while (existingOptions.length && ++r < retryCount && existingOptions.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) {
- candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount);
- }
- return candidate;
-}
-
export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, baseCost: integer): ModifierTypeOption[] {
if (!(waveIndex % 10)) {
return [];
diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts
index c3c62be746f0..0b339906cc54 100644
--- a/src/modifier/modifier.ts
+++ b/src/modifier/modifier.ts
@@ -1307,47 +1307,6 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
}
}
-/**
- * Modifier used for White Herb, which resets negative {@linkcode Stat} changes
- * @extends PokemonHeldItemModifier
- * @see {@linkcode apply}
- */
-export class PokemonResetNegativeStatStageModifier extends PokemonHeldItemModifier {
- constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
- super(type, pokemonId, stackCount);
- }
-
- matchType(modifier: Modifier) {
- return modifier instanceof PokemonResetNegativeStatStageModifier;
- }
-
- clone() {
- return new PokemonResetNegativeStatStageModifier(this.type, this.pokemonId, this.stackCount);
- }
-
- /**
- * Restores any negative stat stages of the mon to 0
- * @param args args[0] is the {@linkcode Pokemon} whose stat stages are being checked
- * @returns true if any stat changes were applied (item was used), false otherwise
- */
- apply(args: any[]): boolean {
- const pokemon = args[0] as Pokemon;
- const loweredStats = pokemon.summonData.battleStats.filter(s => s < 0);
- if (loweredStats.length) {
- for (let s = 0; s < pokemon.summonData.battleStats.length; s++) {
- pokemon.summonData.battleStats[s] = Math.max(0, pokemon.summonData.battleStats[s]);
- }
- pokemon.scene.queueMessage(getPokemonMessage(pokemon, `'s lowered stats were'\nrestored by its ${this.type.name}!`));
- return true;
- }
- return false;
- }
-
- getMaxHeldItemCount(pokemon: Pokemon): integer {
- return 2;
- }
-}
-
export abstract class ConsumablePokemonModifier extends ConsumableModifier {
public pokemonId: integer;
diff --git a/src/overrides.ts b/src/overrides.ts
index 710c94572b13..3e8949678935 100644
--- a/src/overrides.ts
+++ b/src/overrides.ts
@@ -1,24 +1,23 @@
-import {WeatherType} from "./data/weather";
-import {Variant} from "./data/variant";
-import {TempBattleStat} from "./data/temp-battle-stat";
-import {Nature} from "./data/nature";
-import {Type} from "./data/type";
-import {Stat} from "./data/pokemon-stat";
-import {PokeballCounts} from "./battle-scene";
-import {PokeballType} from "./data/pokeball";
-import {Gender} from "./data/gender";
-import {StatusEffect} from "./data/status-effect";
-import {modifierTypes, SpeciesStatBoosterItem} from "./modifier/modifier-type";
-import {VariantTier} from "./enums/variant-tiers";
-import {EggTier} from "#enums/egg-type";
-import {Abilities} from "#enums/abilities";
-import {BerryType} from "#enums/berry-type";
-import {Biome} from "#enums/biome";
-import {Moves} from "#enums/moves";
-import {Species} from "#enums/species";
-import {TimeOfDay} from "#enums/time-of-day";
-import {MysteryEncounterType} from "#enums/mystery-encounter-type"; // eslint-disable-line @typescript-eslint/no-unused-vars
-import {MysteryEncounterTier} from "#app/data/mystery-encounter"; // eslint-disable-line @typescript-eslint/no-unused-vars
+import { WeatherType } from "./data/weather";
+import { Variant } from "./data/variant";
+import { TempBattleStat } from "./data/temp-battle-stat";
+import { Nature } from "./data/nature";
+import { Type } from "./data/type";
+import { Stat } from "./data/pokemon-stat";
+import { PokeballCounts } from "./battle-scene";
+import { PokeballType } from "./data/pokeball";
+import { Gender } from "./data/gender";
+import { StatusEffect } from "./data/status-effect";
+import { SpeciesStatBoosterItem, modifierTypes } from "./modifier/modifier-type";
+import { VariantTier } from "./enums/variant-tiers";
+import { EggTier } from "#enums/egg-type";
+import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars
+import { Abilities } from "#enums/abilities";
+import { BerryType } from "#enums/berry-type";
+import { Biome } from "#enums/biome";
+import { Moves } from "#enums/moves";
+import { Species } from "#enums/species";
+import { TimeOfDay } from "#enums/time-of-day";
/**
* Overrides for testing different in game situations
@@ -112,15 +111,6 @@ export const EGG_VARIANT_OVERRIDE: VariantTier = null;
export const EGG_FREE_GACHA_PULLS_OVERRIDE: boolean = false;
export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
-/**
- * MYSTERY ENCOUNTER OVERRIDES
- */
-
-// 1 to 256, set to null to ignore
-export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null;
-export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
-export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null;
-
/**
* MODIFIER / ITEM OVERRIDES
* if count is not provided, it will default to 1
diff --git a/src/phases.ts b/src/phases.ts
index 4b54fc8d289a..40084520c9c1 100644
--- a/src/phases.ts
+++ b/src/phases.ts
@@ -1,11 +1,11 @@
import BattleScene, { bypassLogin } from "./battle-scene";
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
import * as Utils from "./utils";
-import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr, MoveHeaderAttr } from "./data/move";
+import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr } from "./data/move";
import { Mode } from "./ui/ui";
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
-import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier, PokemonResetNegativeStatStageModifier } from "./modifier/modifier";
+import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier, overrideModifiers, overrideHeldItems, BypassSpeedChanceModifier, TurnStatusEffectModifier } from "./modifier/modifier";
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims";
@@ -17,9 +17,9 @@ import { Phase } from "./phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat";
import { biomeLinks, getBiomeName } from "./data/biomes";
import { ModifierTier } from "./modifier/modifier-tier";
-import { ModifierPoolType, ModifierType, ModifierTypeFunc, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
+import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
-import { BattlerTagLapseType, CenterOfAttentionTag, EncoreTag, ProtectedTag, SemiInvulnerableTag, TrappedTag, MysteryEncounterPostSummonTag } from "./data/battler-tags";
+import { BattlerTagLapseType, CenterOfAttentionTag, EncoreTag, ProtectedTag, SemiInvulnerableTag, TrappedTag } from "./data/battler-tags";
import { getPokemonMessage, getPokemonNameWithAffix } from "./messages";
import { Starter } from "./ui/starter-select-ui-handler";
import { Gender } from "./data/gender";
@@ -40,6 +40,7 @@ import { SessionSaveData } from "./system/game-data";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";
+import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler";
import { SettingKeys } from "./system/settings/settings";
import { Tutorial, handleTutorial } from "./tutorial";
import { TerrainType } from "./data/terrain";
@@ -50,7 +51,7 @@ import { GameMode, GameModes, getGameMode } from "./game-mode";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
import i18next from "./plugins/i18n";
import * as Overrides from "./overrides";
-import { TextStyle, addTextObject, getTextColor } from "./ui/text";
+import { TextStyle, addTextObject } from "./ui/text";
import { Type } from "./data/type";
import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene";
import { Abilities } from "#enums/abilities";
@@ -64,11 +65,6 @@ import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type";
-import {BattlePhase} from "#app/phases/battle-phase";
-import {MysteryEncounterVariant} from "#app/data/mystery-encounter";
-import {MysteryEncounterPhase} from "#app/phases/mystery-encounter-phase";
-import {handleMysteryEncounterVictory} from "#app/data/mystery-encounters/mystery-encounter-utils";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
const { t } = i18next;
@@ -640,6 +636,50 @@ export class SelectStarterPhase extends Phase {
}
}
+export class BattlePhase extends Phase {
+ constructor(scene: BattleScene) {
+ super(scene);
+ }
+
+ showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void {
+ const sprites = this.scene.currentBattle.trainer.getSprites();
+ const tintSprites = this.scene.currentBattle.trainer.getTintSprites();
+ for (let i = 0; i < sprites.length; i++) {
+ const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2;
+ [sprites[i], tintSprites[i]].map(sprite => {
+ if (visible) {
+ sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16;
+ }
+ sprite.setVisible(visible);
+ sprite.clearTint();
+ });
+ sprites[i].setVisible(visible);
+ tintSprites[i].setVisible(visible);
+ sprites[i].clearTint();
+ tintSprites[i].clearTint();
+ }
+ this.scene.tweens.add({
+ targets: this.scene.currentBattle.trainer,
+ x: "-=16",
+ y: "+=16",
+ alpha: 1,
+ ease: "Sine.easeInOut",
+ duration: 750
+ });
+ }
+
+ hideEnemyTrainer(): void {
+ this.scene.tweens.add({
+ targets: this.scene.currentBattle.trainer,
+ x: "+=16",
+ y: "-=16",
+ alpha: 0,
+ ease: "Sine.easeInOut",
+ duration: 750
+ });
+ }
+}
+
type PokemonFunc = (pokemon: Pokemon) => void;
export abstract class FieldPhase extends BattlePhase {
@@ -774,24 +814,6 @@ export class EncounterPhase extends BattlePhase {
const battle = this.scene.currentBattle;
- // Init Mystery Encounter if there is one
- const mysteryEncounter = battle.mysteryEncounter;
- if (mysteryEncounter) {
- // If ME has an onInit() function, call it
- // Usually used for calculating rand data before initializing anything visual
- // Also prepopulates any dialogue tokens from encounter/option requirements
- this.scene.executeWithSeedOffset(() => {
- if (mysteryEncounter.onInit) {
- mysteryEncounter.onInit(this.scene);
- }
- mysteryEncounter.populateDialogueTokensFromRequirements();
- }, this.scene.currentBattle.waveIndex);
-
- // Add intro visuals for mystery encounter
- mysteryEncounter.initIntroVisuals(this.scene);
- this.scene.field.add(mysteryEncounter.introVisuals);
- }
-
let totalBst = 0;
battle.enemyLevels.forEach((level, e) => {
@@ -816,7 +838,7 @@ export class EncounterPhase extends BattlePhase {
}
if (!this.loaded) {
- this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER || battle?.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE);
+ this.scene.gameData.setPokemonSeen(enemyPokemon, true, battle.battleType === BattleType.TRAINER);
}
if (enemyPokemon.species.speciesId === Species.ETERNATUS) {
@@ -845,12 +867,6 @@ export class EncounterPhase extends BattlePhase {
if (battle.battleType === BattleType.TRAINER) {
loadEnemyAssets.push(battle.trainer.loadAssets().then(() => battle.trainer.initSprite()));
- } else if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- if (!battle.mysteryEncounter) {
- const newEncounter = this.scene.getMysteryEncounter(mysteryEncounter);
- battle.mysteryEncounter = newEncounter;
- }
- loadEnemyAssets.push(battle.mysteryEncounter.introVisuals.loadAssets().then(() => battle.mysteryEncounter.introVisuals.initSprite()));
} else {
// This block only applies for double battles to init the boss segments (idk why it's split up like this)
if (battle.enemyParty.filter(p => p.isBoss()).length > 1) {
@@ -878,9 +894,6 @@ export class EncounterPhase extends BattlePhase {
} else if (battle.battleType === BattleType.TRAINER) {
enemyPokemon.setVisible(false);
this.scene.currentBattle.trainer.tint(0, 0.5);
- } else if (battle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- enemyPokemon.setVisible(false);
- this.scene.currentBattle?.trainer?.tint(0, 0.5);
}
if (battle.double) {
enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT);
@@ -932,8 +945,8 @@ export class EncounterPhase extends BattlePhase {
const enemyField = this.scene.getEnemyField();
this.scene.tweens.add({
- targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.currentBattle?.mysteryEncounter?.introVisuals, this.scene.arenaPlayer, this.scene.trainer].flat(),
- x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 3 + (enemyField.length) ? value + 300 : value - 300,
+ targets: [this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer].flat(),
+ x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300,
duration: 2000,
onComplete: () => {
if (!this.tryOverrideForBattleSpec()) {
@@ -1027,54 +1040,6 @@ export class EncounterPhase extends BattlePhase {
showDialogueAndSummon();
}
}
- } else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- const introVisuals = this.scene.currentBattle.mysteryEncounter.introVisuals;
- introVisuals.playAnim();
-
- const doEncounter = () => {
- this.scene.playBgm(undefined);
-
- const doShowEncounterOptions = () => {
- this.scene.ui.clearText();
- this.scene.ui.getMessageHandler().hideNameText();
- this.scene.unshiftPhase(new MysteryEncounterPhase(this.scene));
-
- this.end();
- };
-
- if (showEncounterMessage) {
- const introDialogue = this.scene.currentBattle.mysteryEncounter.dialogue.intro;
- let i = 0;
- const showNextDialogue = () => {
- const nextAction = i === introDialogue.length - 1 ? doShowEncounterOptions : showNextDialogue;
- const dialogue = introDialogue[i];
- const title = dialogue.speaker;
- const text = dialogue.text;
- if (title) {
- this.scene.ui.showDialogue(i18next.t(text), i18next.t(title), null, nextAction, 0, i === 0 ? 750 : 0);
- } else {
- this.scene.ui.showText(i18next.t(text), null, nextAction, i === 0 ? 750 : 0, true);
- }
- i++;
- };
-
- if (introDialogue.length > 0) {
- showNextDialogue();
- }
- } else {
- doShowEncounterOptions();
- }
- };
-
- const encounterMessage = i18next.t("battle:mysteryEncounterAppeared");
-
- if (!encounterMessage) {
- doEncounter();
- } else {
- this.scene.ui.showDialogue(encounterMessage, "???", null, () => {
- this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doEncounter()));
- });
- }
}
}
@@ -1087,7 +1052,7 @@ export class EncounterPhase extends BattlePhase {
}
});
- if (this.scene.currentBattle.battleType !== BattleType.TRAINER && this.scene.currentBattle.battleType !== BattleType.MYSTERY_ENCOUNTER) {
+ if (this.scene.currentBattle.battleType !== BattleType.TRAINER) {
enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
// if there is not a player party, we can't continue
if (!this.scene.getParty()?.length) {
@@ -1181,17 +1146,8 @@ export class NextEncounterPhase extends EncounterPhase {
this.scene.arenaNextEnemy.setVisible(true);
const enemyField = this.scene.getEnemyField();
- const moveTargets: any[] = [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer];
- const lastEncounterVisuals = this.scene?.lastMysteryEncounter?.introVisuals;
- if (lastEncounterVisuals) {
- moveTargets.push(lastEncounterVisuals);
- }
- const nextEncounterVisuals = this.scene.currentBattle?.mysteryEncounter?.introVisuals;
- if (nextEncounterVisuals) {
- moveTargets.push(nextEncounterVisuals);
- }
this.scene.tweens.add({
- targets: moveTargets.flat(),
+ targets: [this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.lastEnemyTrainer].flat(),
x: "+=300",
duration: 2000,
onComplete: () => {
@@ -1203,11 +1159,6 @@ export class NextEncounterPhase extends EncounterPhase {
if (this.scene.lastEnemyTrainer) {
this.scene.lastEnemyTrainer.destroy();
}
- if (lastEncounterVisuals) {
- this.scene.field.remove(lastEncounterVisuals);
- lastEncounterVisuals.destroy();
- this.scene.lastMysteryEncounter.introVisuals = null;
- }
if (!this.tryOverrideForBattleSpec()) {
this.doEncounterCommon();
@@ -1238,14 +1189,8 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
}
const enemyField = this.scene.getEnemyField();
- const moveTargets: any[] = [this.scene.arenaEnemy, enemyField];
- const mysteryEncounter = this.scene.currentBattle?.mysteryEncounter?.introVisuals;
- if (mysteryEncounter) {
- moveTargets.push(mysteryEncounter);
- }
-
this.scene.tweens.add({
- targets: moveTargets.flat(),
+ targets: [this.scene.arenaEnemy, enemyField].flat(),
x: "+=300",
duration: 2000,
onComplete: () => {
@@ -1271,12 +1216,6 @@ export class PostSummonPhase extends PokemonPhase {
pokemon.status.turnCount = 0;
}
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
-
- // If this is fight or flight mystery encounter and is enemy pokemon summon phase, add enraged tag
- if (pokemon.findTags(t => t instanceof MysteryEncounterPostSummonTag)) {
- pokemon.lapseTag(BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON);
- }
-
applyPostSummonAbAttrs(PostSummonAbAttr, pokemon).then(() => this.end());
}
}
@@ -1437,7 +1376,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
preSummon(): void {
const partyMember = this.getPokemon();
// If the Pokemon about to be sent out is fainted or illegal under a challenge, switch to the first non-fainted legal Pokemon
- if (!partyMember.isAllowedInBattle() || (this.player && !this.getParty().some(p => p.id === partyMember.id))) {
+ if (!partyMember.isAllowedInBattle()) {
console.warn("The Pokemon about to be sent out is fainted or illegal under a challenge. Attempting to resolve...");
// First check if they're somehow still in play, if so remove them.
@@ -1485,16 +1424,13 @@ export class SummonPhase extends PartyMemberPokemonPhase {
onComplete: () => this.scene.trainer.setVisible(false)
});
this.scene.time.delayedCall(750, () => this.summon());
- } else if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene?.currentBattle?.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
+ } else {
const trainerName = this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER);
const pokemonName = this.getPokemon().name;
const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName });
this.scene.pbTrayEnemy.hide();
this.scene.ui.showText(message, null, () => this.summon());
- } else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- this.scene.pbTrayEnemy.hide();
- this.summonWild();
}
}
@@ -1576,57 +1512,6 @@ export class SummonPhase extends PartyMemberPokemonPhase {
});
}
- summonWild(): void {
- const pokemon = this.getPokemon();
-
- if (this.fieldIndex === 1) {
- pokemon.setFieldPosition(FieldPosition.RIGHT, 0);
- } else {
- const availablePartyMembers = this.getParty().filter(p => !p.isFainted()).length;
- pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT);
- }
-
- this.scene.add.existing(pokemon);
- this.scene.field.add(pokemon);
- if (!this.player) {
- const playerPokemon = this.scene.getPlayerPokemon() as Pokemon;
- if (playerPokemon?.visible) {
- this.scene.field.moveBelow(pokemon, playerPokemon);
- }
- this.scene.currentBattle.seenEnemyPartyMemberIds.add(pokemon.id);
- }
- this.scene.updateModifiers(this.player);
- this.scene.updateFieldScale();
- pokemon.showInfo();
- pokemon.playAnim();
- pokemon.setVisible(true);
- pokemon.getSprite().setVisible(true);
- pokemon.setScale(0.75);
- pokemon.tint(getPokeballTintColor(pokemon.pokeball));
- pokemon.untint(250, "Sine.easeIn");
- this.scene.updateFieldScale();
- pokemon.x += 16;
- pokemon.y -= 16;
- pokemon.alpha = 0;
-
- // Ease pokemon in
- this.scene.tweens.add({
- targets: pokemon,
- x: "-=16",
- y: "+=16",
- alpha: 1,
- duration: 1000,
- ease: "Sine.easeIn",
- scale: pokemon.getSpriteScale(),
- onComplete: () => {
- pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
- pokemon.getSprite().clearTint();
- pokemon.resetSummonData();
- this.scene.time.delayedCall(1000, () => this.end());
- }
- });
- }
-
onEnd(): void {
const pokemon = this.getPokemon();
@@ -1636,7 +1521,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
pokemon.resetTurnData();
- if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER || (this.scene.currentBattle.waveIndex % 10) === 1) {
+ if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) {
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
this.queuePostSummon();
}
@@ -1698,10 +1583,6 @@ export class SwitchSummonPhase extends SummonPhase {
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
}
- if (!pokemon.isActive() || !pokemon.isOnField()) {
- this.switchAndSummon();
- }
-
this.scene.ui.showText(this.player ?
i18next.t("battle:playerComeBack", { pokemonName: pokemon.name }) :
i18next.t("battle:trainerComeBack", {
@@ -2120,13 +2001,6 @@ export class CommandPhase extends FieldPhase {
this.scene.ui.showText(null, 0);
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
}, null, true);
- } else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER && !this.scene.currentBattle.mysteryEncounter.catchAllowed) {
- this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
- this.scene.ui.setMode(Mode.MESSAGE);
- this.scene.ui.showText(i18next.t("battle:noPokeballMysteryEncounter"), null, () => {
- this.scene.ui.showText(null, 0);
- this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
- }, null, true);
} else {
const targets = this.scene.getEnemyField().filter(p => p.isActive(true)).map(p => p.getBattlerIndex());
if (targets.length > 1) {
@@ -2412,14 +2286,12 @@ export class TurnStartPhase extends FieldPhase {
return aIndex < bIndex ? -1 : aIndex > bIndex ? 1 : 0;
});
- this.queueMoveHeaders(moveOrder);
for (const o of moveOrder) {
const pokemon = field[o];
const turnCommand = this.scene.currentBattle.turnCommands[o];
if (turnCommand.skip) {
- this.scene.tryRemovePhase(phase => phase instanceof MoveHeaderPhase && phase.pokemon === pokemon);
continue;
}
@@ -2483,30 +2355,8 @@ export class TurnStartPhase extends FieldPhase {
this.scene.pushPhase(new BerryPhase(this.scene));
this.scene.pushPhase(new TurnEndPhase(this.scene));
- /**
- * this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front
- * of the queue and dequeues to start the next phase
- * this is important since stuff like SwitchSummon, AttemptRun, AttemptCapture Phases break the "flow" and should take precedence
- */
this.end();
}
-
- queueMoveHeaders(moveOrder: BattlerIndex[]): void {
- moveOrder.forEach(o => {
- const pokemon = this.scene.getField()[o];
- const turnCommand = this.scene.currentBattle.turnCommands[o];
-
- if (turnCommand.command === Command.FIGHT) {
- const queuedMove = turnCommand.move;
- if (!!queuedMove) {
- const move = pokemon.getMoveset().find(m => m.moveId === queuedMove.move) || new PokemonMove(queuedMove.move);
- if (move.getMove().hasAttr(MoveHeaderAttr)) {
- this.scene.pushPhase(new MoveHeaderPhase(this.scene, pokemon, move));
- }
- }
- }
- });
- }
}
/** The phase after attacks where the pokemon eat berries */
@@ -2691,96 +2541,6 @@ export class CommonAnimPhase extends PokemonPhase {
}
}
-export class MoveHeaderPhase extends BattlePhase {
- public pokemon: Pokemon;
- public move: PokemonMove;
-
- constructor(scene: BattleScene, pokemon: Pokemon, move: PokemonMove) {
- super(scene);
-
- this.pokemon = pokemon;
- this.move = move;
- }
-
- canMove(): boolean {
- return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, true);
- }
-
- start() {
- super.start();
-
- if (this.canMove()) {
- /**
- * Preemptively apply status effects (Paralysis, Sleep, and Freeze).
- * If this move would be cancelled by the user's status, it's cancelled
- * here before applying header effects.
- * If the user has one of these statuses, but the move isn't cancelled, the same status
- * check in this move's respective `MovePhase` is ignored.
- */
- if (this.pokemon.status && !this.pokemon.status.isPostTurn()) {
- this.pokemon.status.incrementTurn();
- let activated = false;
- let healed = false;
-
- switch (this.pokemon.status.effect) {
- case StatusEffect.PARALYSIS:
- if (!this.pokemon.randSeedInt(4)) {
- activated = true;
- }
- break;
- case StatusEffect.SLEEP:
- healed = this.pokemon.status.turnCount === this.pokemon.status.cureTurn;
- activated = !healed;
- break;
- case StatusEffect.FREEZE:
- healed = !!this.move.getMove().findAttr(attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE)) || !this.pokemon.randSeedInt(5);
- activated = !healed;
- break;
- }
-
- if (activated) {
- this.scene.queueMessage(getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
- this.scene.unshiftPhase(new CommonAnimPhase(this.scene, this.pokemon.getBattlerIndex(), undefined, CommonAnim.POISON + (this.pokemon.status.effect - 1)));
- this.cancelMove();
- this.end();
- } else {
- if (healed) {
- this.scene.queueMessage(getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)));
- this.pokemon.resetStatus();
- this.pokemon.updateInfo();
- }
- const movePhase = this.scene.findPhase(phase => phase instanceof MovePhase && phase.pokemon === this.pokemon);
- if (movePhase instanceof MovePhase) {
- movePhase.setIgnoreStatusCheck();
- }
- applyMoveAttrs(MoveHeaderAttr, this.pokemon, null, this.move.getMove()).then(() => this.end());
- }
- } else {
- applyMoveAttrs(MoveHeaderAttr, this.pokemon, null, this.move.getMove()).then(() => this.end());
- }
- } else {
- this.end();
- }
- }
-
- cancelMove(): void {
- this.pokemon.turnData.acted = true; // Record that the move was attempted
-
- this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE);
-
- const moveQueue = this.pokemon.getMoveQueue();
-
- // Record a failed move so Abilities like Truant don't trigger next turn and soft-lock
- this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL });
-
- this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT); // Remove any tags from moves like Fly/Dive/etc.
- moveQueue.shift(); // Remove the second turn of charge moves
-
- // Remove the MovePhase from this turn with the same user Pokemon
- this.scene.tryRemovePhase(phase => phase instanceof MovePhase && phase.pokemon === this.pokemon);
- }
-}
-
export class MovePhase extends BattlePhase {
public pokemon: Pokemon;
public move: PokemonMove;
@@ -2789,7 +2549,6 @@ export class MovePhase extends BattlePhase {
protected ignorePp: boolean;
protected failed: boolean;
protected cancelled: boolean;
- protected ignoreStatusCheck: boolean;
constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp?: boolean, ignorePp?: boolean) {
super(scene);
@@ -2801,7 +2560,6 @@ export class MovePhase extends BattlePhase {
this.ignorePp = !!ignorePp;
this.failed = false;
this.cancelled = false;
- this.ignoreStatusCheck = false;
}
canMove(): boolean {
@@ -2889,7 +2647,6 @@ export class MovePhase extends BattlePhase {
return false;
});
- // Readability?: this function declaration honestly gets in the way of readability of what start() is doing , move either to beginning or end
const doMove = () => {
this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails
@@ -2998,7 +2755,7 @@ export class MovePhase extends BattlePhase {
this.end();
};
- if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn() && !this.ignoreStatusCheck) {
+ if (!this.followUp && this.pokemon.status && !this.pokemon.status.isPostTurn()) {
this.pokemon.status.incrementTurn();
let activated = false;
let healed = false;
@@ -3071,10 +2828,6 @@ export class MovePhase extends BattlePhase {
this.scene.queueMessage(failedText || i18next.t("battle:attackFailed"));
}
- setIgnoreStatusCheck(): void {
- this.ignoreStatusCheck = true;
- }
-
end() {
if (!this.followUp && this.canMove()) {
this.scene.unshiftPhase(new MoveEndPhase(this.scene, this.pokemon.getBattlerIndex()));
@@ -3257,11 +3010,8 @@ export class MoveEffectPhase extends PokemonPhase {
if (--user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) {
this.scene.unshiftPhase(this.getNewHitPhase());
} else {
- // queue message for number of hits made by multi-move
- // if multi-hit attack only hits once, still want to render a message
const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0);
- if (hitsTotal > 1 || user.turnData.hitsLeft > 0) {
- // if there are multiple hits, or if there are hits of the multi-hit move left
+ if (hitsTotal > 1) {
this.scene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal }));
}
this.scene.applyModifiers(HitHealModifier, this.player, user);
@@ -3297,10 +3047,6 @@ export class MoveEffectPhase extends PokemonPhase {
return true;
}
- if (target.getTag(BattlerTagType.ALWAYS_GET_HIT)) {
- return true;
- }
-
const hiddenTag = target.getTag(SemiInvulnerableTag);
if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === hiddenTag.tagType)) {
return false;
@@ -3556,20 +3302,6 @@ export class StatChangePhase extends PokemonPhase {
applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget);
- //Look for any other stat change phases; if this is the last one, do White Herb check
- const existingPhase = this.scene.findPhase(p => p instanceof StatChangePhase && p.battlerIndex === this.battlerIndex);
- if (!(existingPhase instanceof StatChangePhase)) {
- // Apply White Herb if needed
- const whiteHerb = this.scene.applyModifier(PokemonResetNegativeStatStageModifier, this.player, pokemon) as PokemonResetNegativeStatStageModifier;
- // If the White Herb was applied, consume it
- if (whiteHerb) {
- if (!--whiteHerb.stackCount) {
- this.scene.removeModifier(whiteHerb);
- }
- this.scene.updateModifiers(this.player);
- }
- }
-
pokemon.updateInfo();
handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end());
@@ -3679,13 +3411,12 @@ export class StatChangePhase extends PokemonPhase {
if (relLevelStats.length > 1) {
statsFragment = relLevelStats.length >= 5
- ? i18next.t("battle:stats")
- : `${relLevelStats.slice(0, -1).map(s => getBattleStatName(s)).join(", ")}${relLevelStats.length > 2 ? "," : ""} ${i18next.t("battle:statsAnd")} ${getBattleStatName(relLevelStats[relLevelStats.length - 1])}`;
- messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1,true));
+ ? "stats"
+ : `${relLevelStats.slice(0, -1).map(s => getBattleStatName(s)).join(", ")}${relLevelStats.length > 2 ? "," : ""} and ${getBattleStatName(relLevelStats[relLevelStats.length - 1])}`;
} else {
statsFragment = getBattleStatName(relLevelStats[0]);
- messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1));
}
+ messages.push(getBattleStatLevelChangeDescription(getPokemonNameWithAffix(this.getPokemon()), statsFragment, Math.abs(parseInt(rl)), levels >= 1));
});
return messages;
@@ -4041,7 +3772,7 @@ export class FaintPhase extends PokemonPhase {
}
} else {
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
- if (this.scene.currentBattle.battleType === BattleType.TRAINER || this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
+ if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
const hasReservePartyMember = !!this.scene.getEnemyParty().filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot).length;
if (hasReservePartyMember) {
this.scene.pushPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, -1, false, false, false));
@@ -4137,8 +3868,6 @@ export class VictoryPhase extends PokemonPhase {
let expValue = this.getPokemon().getExpValue();
if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
expValue = Math.floor(expValue * 1.5);
- } else if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- expValue = Math.floor(expValue * this.scene.currentBattle.mysteryEncounter.expMultiplier);
}
for (const partyMember of nonFaintedPartyMembers) {
const pId = partyMember.id;
@@ -4207,13 +3936,7 @@ export class VictoryPhase extends PokemonPhase {
}
}
- if (this.scene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER) {
- handleMysteryEncounterVictory(this.scene);
- this.end();
- return;
- }
-
- if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType === BattleType.WILD ? p.isOnField() : !p?.isFainted(true))) {
+ if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType ? !p?.isFainted(true) : p.isOnField())) {
this.scene.pushPhase(new BattleEndPhase(this.scene));
if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
this.scene.pushPhase(new TrainerVictoryPhase(this.scene));
@@ -4243,7 +3966,6 @@ export class VictoryPhase extends PokemonPhase {
this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene));
}
}
-
this.scene.pushPhase(new NewBattlePhase(this.scene));
} else {
this.scene.currentBattle.battleType = BattleType.CLEAR;
@@ -4482,6 +4204,15 @@ export class GameOverPhase extends BattlePhase {
this.scene.gameData.gameStats.dailyRunSessionsWon++;
}
}
+
+ this.scene.gameData.getSession(this.scene.sessionSlotId).then(sessionData => {
+ if (sessionData) {
+ this.scene.gameData.saveRunHistory(this.scene, sessionData, this.victory);
+ }
+ }).catch(err => {
+ console.error(err);
+ });
+
const fadeDuration = this.victory ? 10000 : 5000;
this.scene.fadeOutBgm(fadeDuration, true);
const activeBattlers = this.scene.getField().filter(p => p?.isActive(true));
@@ -5060,7 +4791,7 @@ export class AttemptCapturePhase extends PokemonPhase {
const pokemon = this.getPokemon() as EnemyPokemon;
- if (!pokemon?.hp || !!pokemon.getTag(SemiInvulnerableTag) && !pokemon.getTag(BattlerTagType.FLYING)) {
+ if (!pokemon?.hp) {
return this.end();
}
@@ -5352,6 +5083,219 @@ export class AttemptRunPhase extends PokemonPhase {
}
}
+export class SelectModifierPhase extends BattlePhase {
+ private rerollCount: integer;
+ private modifierTiers: ModifierTier[];
+
+ constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[]) {
+ super(scene);
+
+ this.rerollCount = rerollCount;
+ this.modifierTiers = modifierTiers;
+ }
+
+ start() {
+ super.start();
+
+ if (!this.rerollCount) {
+ this.updateSeed();
+ } else {
+ this.scene.reroll = false;
+ }
+
+ const party = this.scene.getParty();
+ regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount);
+ const modifierCount = new Utils.IntegerHolder(3);
+ if (this.isPlayer()) {
+ this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount);
+ }
+ const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value);
+
+ const modifierSelectCallback = (rowCursor: integer, cursor: integer) => {
+ if (rowCursor < 0 || cursor < 0) {
+ this.scene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => {
+ this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
+ this.scene.ui.revertMode();
+ this.scene.ui.setMode(Mode.MESSAGE);
+ super.end();
+ }, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)));
+ });
+ return false;
+ }
+ let modifierType: ModifierType;
+ let cost: integer;
+ switch (rowCursor) {
+ case 0:
+ switch (cursor) {
+ case 0:
+ const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers);
+ if (this.scene.money < rerollCost) {
+ this.scene.ui.playError();
+ return false;
+ } else {
+ this.scene.reroll = true;
+ this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type.tier)));
+ this.scene.ui.clearText();
+ this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
+ this.scene.money -= rerollCost;
+ this.scene.updateMoneyText();
+ this.scene.animateMoneyChanged(false);
+ this.scene.playSound("buy");
+ }
+ break;
+ case 1:
+ this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => {
+ if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) {
+ const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
+ && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[];
+ const itemModifier = itemModifiers[itemIndex];
+ this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity);
+ } else {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ }
+ }, PartyUiHandler.FilterItemMaxStacks);
+ break;
+ case 2:
+ this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ });
+ break;
+ case 3:
+ this.scene.lockModifierTiers = !this.scene.lockModifierTiers;
+ const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
+ uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ uiHandler.updateLockRaritiesText();
+ uiHandler.updateRerollCostText();
+ return false;
+ }
+ return true;
+ case 1:
+ modifierType = typeOptions[cursor].type;
+ break;
+ default:
+ const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1));
+ const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT];
+ modifierType = shopOption.type;
+ cost = shopOption.cost;
+ break;
+ }
+
+ if (cost && this.scene.money < cost) {
+ this.scene.ui.playError();
+ return false;
+ }
+
+ const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
+ const result = this.scene.addModifier(modifier, false, playSound);
+ if (cost) {
+ result.then(success => {
+ if (success) {
+ this.scene.money -= cost;
+ this.scene.updateMoneyText();
+ this.scene.animateMoneyChanged(false);
+ this.scene.playSound("buy");
+ (this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
+ } else {
+ this.scene.ui.playError();
+ }
+ });
+ } else {
+ const doEnd = () => {
+ this.scene.ui.clearText();
+ this.scene.ui.setMode(Mode.MESSAGE);
+ super.end();
+ };
+ if (result instanceof Promise) {
+ result.then(() => doEnd());
+ } else {
+ doEnd();
+ }
+ }
+ };
+
+ if (modifierType instanceof PokemonModifierType) {
+ if (modifierType instanceof FusePokemonModifierType) {
+ this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => {
+ if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
+ const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex]);
+ applyModifier(modifier, true);
+ });
+ } else {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ }
+ }, modifierType.selectFilter);
+ } else {
+ const pokemonModifierType = modifierType as PokemonModifierType;
+ const isMoveModifier = modifierType instanceof PokemonMoveModifierType;
+ const isTmModifier = modifierType instanceof TmModifierType;
+ const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType;
+ const isPpRestoreModifier = (modifierType instanceof PokemonPpRestoreModifierType || modifierType instanceof PokemonPpUpModifierType);
+ const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER
+ : isTmModifier ? PartyUiMode.TM_MODIFIER
+ : isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER
+ : PartyUiMode.MODIFIER;
+ const tmMoveId = isTmModifier
+ ? (modifierType as TmModifierType).moveId
+ : undefined;
+ this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => {
+ if (slotIndex < 6) {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
+ const modifier = !isMoveModifier
+ ? !isRememberMoveModifier
+ ? modifierType.newModifier(party[slotIndex])
+ : modifierType.newModifier(party[slotIndex], option as integer)
+ : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1);
+ applyModifier(modifier, true);
+ });
+ } else {
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ }
+ }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier);
+ }
+ } else {
+ applyModifier(modifierType.newModifier());
+ }
+
+ return !cost;
+ };
+ this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
+ }
+
+ updateSeed(): void {
+ this.scene.resetSeed();
+ }
+
+ isPlayer(): boolean {
+ return true;
+ }
+
+ getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): integer {
+ let baseValue = 0;
+ if (lockRarities) {
+ const tierValues = [50, 125, 300, 750, 2000];
+ for (const opt of typeOptions) {
+ baseValue += tierValues[opt.type.tier];
+ }
+ } else {
+ baseValue = 250;
+ }
+ return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount), Number.MAX_SAFE_INTEGER);
+ }
+
+ getPoolType(): ModifierPoolType {
+ return ModifierPoolType.PLAYER;
+ }
+
+ getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] {
+ return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined);
+ }
+
+ addModifier(modifier: Modifier): Promise {
+ return this.scene.addModifier(modifier, false, true);
+ }
+}
+
export class EggLapsePhase extends Phase {
constructor(scene: BattleScene) {
super(scene);
@@ -5513,45 +5457,19 @@ export class ScanIvsPhase extends PokemonPhase {
const pokemon = this.getPokemon();
- let enemyIvs = [];
- let statsContainer = [];
- let statsContainerLabels = [];
- const enemyField = this.scene.getEnemyField();
- const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible
- for (let e = 0; e < enemyField.length; e++) {
- enemyIvs = enemyField[e].ivs;
- const currentIvs = this.scene.gameData.dexData[enemyField[e].species.speciesId].ivs;
- const ivsToShow = this.scene.ui.getMessageHandler().topIvs(enemyIvs, this.shownIvs);
- statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list;
- statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0);
- for (let s = 0; s < statsContainerLabels.length; s++) {
- const ivStat = Stat[statsContainerLabels[s].frame.name];
- if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) {
- const hexColour = enemyIvs[ivStat] === 31 ? "#f8c020" : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme);
- const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color;
- statsContainerLabels[s].setTint(hexTextColour);
- }
- statsContainerLabels[s].setVisible(true);
- }
- }
-
- if (!this.scene.hideIvs) {
- this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: pokemon.name }), null, () => {
- this.scene.ui.setMode(Mode.CONFIRM, () => {
- this.scene.ui.setMode(Mode.MESSAGE);
- this.scene.ui.clearText();
- new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => {
- this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end());
- });
- }, () => {
- this.scene.ui.setMode(Mode.MESSAGE);
- this.scene.ui.clearText();
- this.end();
+ this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: pokemon.name }), null, () => {
+ this.scene.ui.setMode(Mode.CONFIRM, () => {
+ this.scene.ui.setMode(Mode.MESSAGE);
+ this.scene.ui.clearText();
+ new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => {
+ this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end());
});
+ }, () => {
+ this.scene.ui.setMode(Mode.MESSAGE);
+ this.scene.ui.clearText();
+ this.end();
});
- } else {
- this.end();
- }
+ });
}
}
diff --git a/src/phases/battle-phase.ts b/src/phases/battle-phase.ts
deleted file mode 100644
index 62c35403f3fc..000000000000
--- a/src/phases/battle-phase.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import {Phase} from "#app/phase";
-import BattleScene from "#app/battle-scene";
-import {TrainerSlot} from "#app/data/trainer-config";
-
-export class BattlePhase extends Phase {
- constructor(scene: BattleScene) {
- super(scene);
- }
-
- showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void {
- const sprites = this.scene.currentBattle.trainer.getSprites();
- const tintSprites = this.scene.currentBattle.trainer.getTintSprites();
- for (let i = 0; i < sprites.length; i++) {
- const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2;
- [sprites[i], tintSprites[i]].map(sprite => {
- if (visible) {
- sprite.x = trainerSlot || sprites.length < 2 ? 0 : i ? 16 : -16;
- }
- sprite.setVisible(visible);
- sprite.clearTint();
- });
- sprites[i].setVisible(visible);
- tintSprites[i].setVisible(visible);
- sprites[i].clearTint();
- tintSprites[i].clearTint();
- }
- this.scene.tweens.add({
- targets: this.scene.currentBattle.trainer,
- x: "-=16",
- y: "+=16",
- alpha: 1,
- ease: "Sine.easeInOut",
- duration: 750
- });
- }
-
- hideEnemyTrainer(): void {
- this.scene.tweens.add({
- targets: this.scene.currentBattle.trainer,
- x: "+=16",
- y: "-=16",
- alpha: 0,
- ease: "Sine.easeInOut",
- duration: 750
- });
- }
-}
diff --git a/src/phases/mystery-encounter-phase.ts b/src/phases/mystery-encounter-phase.ts
deleted file mode 100644
index 2700ec32ae18..000000000000
--- a/src/phases/mystery-encounter-phase.ts
+++ /dev/null
@@ -1,473 +0,0 @@
-import i18next from "i18next";
-import BattleScene from "../battle-scene";
-import { Phase } from "../phase";
-import { Mode } from "../ui/ui";
-import {
- getTextWithEncounterDialogueTokens
-} from "../data/mystery-encounters/mystery-encounter-utils";
-import { CheckSwitchPhase, NewBattlePhase, PostSummonPhase, ReturnPhase, ScanIvsPhase, SummonPhase, ToggleDoublePositionPhase } from "../phases";
-import MysteryEncounterOption from "../data/mystery-encounter-option";
-import { MysteryEncounterVariant } from "../data/mystery-encounter";
-import { getCharVariantFromDialogue } from "../data/dialogue";
-import { TrainerSlot } from "../data/trainer-config";
-import { BattleSpec } from "../enums/battle-spec";
-import { Tutorial, handleTutorial } from "../tutorial";
-import { IvScannerModifier } from "../modifier/modifier";
-import * as Utils from "../utils";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
-import {isNullOrUndefined} from "../utils";
-
-/**
- * Will handle (in order):
- * - Clearing of phase queues to enter the Mystery Encounter game state
- * - Management of session data related to MEs
- * - Initialization of ME option select menu and UI
- * - Execute onPreOptionPhase() logic if it exists for the selected option
- * - Display any OptionTextDisplay.selected type dialogue that is set in the MysteryEncounterDialogue dialogue tree for selected option
- * - Queuing of the MysteryEncounterOptionSelectedPhase
- */
-export class MysteryEncounterPhase extends Phase {
- constructor(scene: BattleScene) {
- super(scene);
- }
-
- start() {
- super.start();
-
- // Clears out queued phases that are part of standard battle
- this.scene.clearPhaseQueue();
- this.scene.clearPhaseQueueSplice();
-
- // Sets flag that ME was encountered
- // Can be used in later MEs to check for requirements to spawn, etc.
- this.scene.mysteryEncounterFlags.encounteredEvents.push([this.scene.currentBattle.mysteryEncounter.encounterType, this.scene.currentBattle.mysteryEncounter.encounterTier]);
-
- // Initiates encounter dialogue window and option select
- this.scene.ui.setMode(Mode.MYSTERY_ENCOUNTER);
- }
-
- handleOptionSelect(option: MysteryEncounterOption, index: number): boolean {
- // Set option selected flag
- this.scene.currentBattle.mysteryEncounter.selectedOption = option;
-
- if (!option.onOptionPhase) {
- return false;
- }
-
- // Populate dialogue tokens for option requirements
- this.scene.currentBattle.mysteryEncounter.populateDialogueTokensFromRequirements();
-
- if (option.onPreOptionPhase) {
- this.scene.executeWithSeedOffset(async () => {
- return await option.onPreOptionPhase(this.scene)
- .then((result) => {
- if (isNullOrUndefined(result) || result) {
- this.continueEncounter(index);
- }
- });
- }, this.scene.currentBattle.waveIndex * 1000);
- } else {
- this.continueEncounter(index);
- }
-
- return true;
- }
-
- continueEncounter(optionIndex: number) {
- const endDialogueAndContinueEncounter = () => {
- this.scene.pushPhase(new MysteryEncounterOptionSelectedPhase(this.scene));
- this.end();
- };
-
- const optionSelectDialogue = this.scene.currentBattle?.mysteryEncounter?.dialogue?.encounterOptionsDialogue?.options?.[optionIndex];
- if (optionSelectDialogue?.selected?.length > 0) {
- // Handle intermediate dialogue (between player selection event and the onOptionSelect logic)
- this.scene.ui.setMode(Mode.MESSAGE);
- const selectedDialogue = optionSelectDialogue.selected;
- let i = 0;
- const showNextDialogue = () => {
- const nextAction = i === selectedDialogue.length - 1 ? endDialogueAndContinueEncounter : showNextDialogue;
- const dialogue = selectedDialogue[i];
- let title: string = null;
- const text: string = getTextWithEncounterDialogueTokens(this.scene, dialogue.text);
- if (dialogue.speaker) {
- title = getTextWithEncounterDialogueTokens(this.scene, dialogue.speaker);
- }
-
- if (title) {
- this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 0 ? 750 : 0);
- } else {
- this.scene.ui.showText(text, null, nextAction, i === 0 ? 750 : 0, true);
- }
- i++;
- };
-
- showNextDialogue();
- } else {
- endDialogueAndContinueEncounter();
- }
- }
-
- cancel() {
- this.end();
- }
-
- end() {
- this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
- }
-}
-
-/**
- * Will handle (in order):
- * - Execute onOptionSelect() logic if it exists for the selected option
- *
- * It is important to point out that no phases are directly queued by any logic within this phase
- * Any phase that is meant to follow this one MUST be queued via the onOptionSelect() logic of the selected option
- */
-export class MysteryEncounterOptionSelectedPhase extends Phase {
- onOptionSelect: (scene: BattleScene) => Promise;
-
- constructor(scene: BattleScene) {
- super(scene);
- this.onOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption.onOptionPhase;
- }
-
- start() {
- super.start();
- if (this.scene.currentBattle.mysteryEncounter.hideIntroVisuals) {
- this.hideMysteryEncounterIntroVisuals().then(() => {
- this.scene.executeWithSeedOffset(() => {
- this.onOptionSelect(this.scene).finally(() => {
- this.end();
- });
- }, this.scene.currentBattle.waveIndex * 1000);
- });
- } else {
- this.scene.executeWithSeedOffset(() => {
- this.onOptionSelect(this.scene).finally(() => {
- this.end();
- });
- }, this.scene.currentBattle.waveIndex * 1000);
- }
- }
-
- hideMysteryEncounterIntroVisuals(): Promise {
- return new Promise(resolve => {
- const introVisuals = this.scene.currentBattle.mysteryEncounter.introVisuals;
- if (introVisuals) {
- // Hide
- this.scene.tweens.add({
- targets: introVisuals,
- x: "+=16",
- y: "-=16",
- alpha: 0,
- ease: "Sine.easeInOut",
- duration: 750,
- onComplete: () => {
- this.scene.field.remove(introVisuals);
- introVisuals.setVisible(false);
- introVisuals.destroy();
- this.scene.currentBattle.mysteryEncounter.introVisuals = null;
- resolve(true);
- }
- });
- } else {
- resolve(true);
- }
- });
- }
-}
-
-/**
- * Will handle (in order):
- * - Setting BGM
- * - Showing intro dialogue for an enemy trainer or wild Pokemon
- * - Sliding in the visuals for enemy trainer or wild Pokemon, as well as handling summoning animations
- * - Queue the SummonPhases, PostSummonPhases, etc., required to initialize the phase queue for a battle
- */
-export class MysteryEncounterBattlePhase extends Phase {
- constructor(scene: BattleScene) {
- super(scene);
- }
-
- start() {
- super.start();
-
- this.doMysteryEncounterBattle(this.scene);
- }
-
- getBattleMessage(scene: BattleScene): string {
- const enemyField = scene.getEnemyField();
- const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
-
- if (scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
- return i18next.t("battle:bossAppeared", { bossName: enemyField[0].name });
- }
-
- if (encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
- if (scene.currentBattle.double) {
- return i18next.t("battle:trainerAppearedDouble", { trainerName: scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) });
-
- } else {
- return i18next.t("battle:trainerAppeared", { trainerName: scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) });
- }
- }
-
- return enemyField.length === 1
- ? i18next.t("battle:singleWildAppeared", { pokemonName: enemyField[0].name })
- : i18next.t("battle:multiWildAppeared", { pokemonName1: enemyField[0].name, pokemonName2: enemyField[1].name });
- }
-
- doMysteryEncounterBattle(scene: BattleScene) {
- const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
- if (encounterVariant === MysteryEncounterVariant.WILD_BATTLE || encounterVariant === MysteryEncounterVariant.BOSS_BATTLE) {
- // Summons the wild/boss Pokemon
- if (encounterVariant === MysteryEncounterVariant.BOSS_BATTLE) {
- scene.playBgm(undefined);
- }
- const availablePartyMembers = scene.getEnemyParty().filter(p => !p.isFainted()).length;
- scene.unshiftPhase(new SummonPhase(scene, 0, false));
- if (scene.currentBattle.double && availablePartyMembers > 1) {
- scene.unshiftPhase(new SummonPhase(scene, 1, false));
- }
-
- if (!scene.currentBattle.mysteryEncounter.hideBattleIntroMessage) {
- scene.ui.showText(this.getBattleMessage(scene), null, () => this.endBattleSetup(scene), 1500);
- } else {
- this.endBattleSetup(scene);
- }
- } else if (encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
- this.showEnemyTrainer();
- const doSummon = () => {
- scene.currentBattle.started = true;
- scene.playBgm(undefined);
- scene.pbTray.showPbTray(scene.getParty());
- scene.pbTrayEnemy.showPbTray(scene.getEnemyParty());
- const doTrainerSummon = () => {
- this.hideEnemyTrainer();
- const availablePartyMembers = scene.getEnemyParty().filter(p => !p.isFainted()).length;
- scene.unshiftPhase(new SummonPhase(scene, 0, false));
- if (scene.currentBattle.double && availablePartyMembers > 1) {
- scene.unshiftPhase(new SummonPhase(scene, 1, false));
- }
- this.endBattleSetup(scene);
- };
- if (!scene.currentBattle.mysteryEncounter.hideBattleIntroMessage) {
- scene.ui.showText(this.getBattleMessage(scene), null, doTrainerSummon, 1500, true);
- } else {
- doTrainerSummon();
- }
- };
-
- const encounterMessages = scene.currentBattle.trainer.getEncounterMessages();
-
- if (!encounterMessages?.length) {
- doSummon();
- } else {
- const trainer = this.scene.currentBattle.trainer;
- let message: string;
- scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), scene.currentBattle.waveIndex * 1000);
-
- const showDialogueAndSummon = () => {
- scene.ui.showDialogue(message, trainer.getName(TrainerSlot.NONE, true), null, () => {
- scene.charSprite.hide().then(() => scene.hideFieldOverlay(250).then(() => doSummon()));
- });
- };
- if (scene.currentBattle.trainer.config.hasCharSprite && !scene.ui.shouldSkipDialogue(message)) {
- scene.showFieldOverlay(500).then(() => scene.charSprite.showCharacter(trainer.getKey(), getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon()));
- } else {
- showDialogueAndSummon();
- }
- }
- }
- }
-
- endBattleSetup(scene: BattleScene) {
- const enemyField = scene.getEnemyField();
- const encounterVariant = scene.currentBattle.mysteryEncounter.encounterVariant;
-
- if (encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE) {
- enemyField.map(p => this.scene.pushConditionalPhase(new PostSummonPhase(this.scene, p.getBattlerIndex()), () => {
- // if there is not a player party, we can't continue
- if (!this.scene.getParty()?.length) {
- return false;
- }
- // how many player pokemon are on the field ?
- const pokemonsOnFieldCount = this.scene.getParty().filter(p => p.isOnField()).length;
- // if it's a 2vs1, there will never be a 2nd pokemon on our field even
- const requiredPokemonsOnField = Math.min(this.scene.getParty().filter((p) => !p.isFainted()).length, 2);
- // if it's a double, there should be 2, otherwise 1
- if (this.scene.currentBattle.double) {
- return pokemonsOnFieldCount === requiredPokemonsOnField;
- }
- return pokemonsOnFieldCount === 1;
- }));
- const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier);
- if (ivScannerModifier) {
- enemyField.map(p => this.scene.pushPhase(new ScanIvsPhase(this.scene, p.getBattlerIndex(), Math.min(ivScannerModifier.getStackCount() * 2, 6))));
- }
- }
-
- const availablePartyMembers = scene.getParty().filter(p => !p.isFainted());
-
- if (!availablePartyMembers[0].isOnField()) {
- scene.pushPhase(new SummonPhase(scene, 0));
- }
-
- if (scene.currentBattle.double) {
- if (availablePartyMembers.length > 1) {
- scene.pushPhase(new ToggleDoublePositionPhase(scene, true));
- if (!availablePartyMembers[1].isOnField()) {
- scene.pushPhase(new SummonPhase(scene, 1));
- }
- }
- } else {
- if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) {
- scene.pushPhase(new ReturnPhase(scene, 1));
- }
- scene.pushPhase(new ToggleDoublePositionPhase(scene, false));
- }
-
- if (encounterVariant !== MysteryEncounterVariant.TRAINER_BATTLE && (scene.currentBattle.waveIndex > 1 || !scene.gameMode.isDaily)) {
- const minPartySize = scene.currentBattle.double ? 2 : 1;
- if (availablePartyMembers.length > minPartySize) {
- scene.pushPhase(new CheckSwitchPhase(scene, 0, scene.currentBattle.double));
- if (scene.currentBattle.double) {
- scene.pushPhase(new CheckSwitchPhase(scene, 1, scene.currentBattle.double));
- }
- }
- }
-
- // TODO: remove?
- handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
- }
-
- showEnemyTrainer(): void {
- // Show enemy trainer
- const trainer = this.scene.currentBattle.trainer;
- trainer.alpha = 0;
- trainer.x += 16;
- trainer.y -= 16;
- trainer.setVisible(true);
- this.scene.tweens.add({
- targets: trainer,
- x: "-=16",
- y: "+=16",
- alpha: 1,
- ease: "Sine.easeInOut",
- duration: 750,
- onComplete: () => {
- trainer.untint(100, "Sine.easeOut");
- trainer.playAnim();
- }
- });
- }
-
- hideEnemyTrainer(): void {
- this.scene.tweens.add({
- targets: this.scene.currentBattle.trainer,
- x: "+=16",
- y: "-=16",
- alpha: 0,
- ease: "Sine.easeInOut",
- duration: 750
- });
- }
-}
-
-/**
- * Will handle (in order):
- * - Any encounter reward logic that is set within MysteryEncounter doEncounterRewards
- * - Otherwise, can add a no-reward-item shop with only Potions, etc. if addHealPhase is true
- * - Queuing of the PostMysteryEncounterPhase
- */
-export class MysteryEncounterRewardsPhase extends Phase {
- addHealPhase: boolean;
-
- constructor(scene: BattleScene, addHealPhase: boolean = false) {
- super(scene);
- this.addHealPhase = addHealPhase;
- }
-
- start() {
- super.start();
-
- this.scene.executeWithSeedOffset(() => {
- if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
- this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
- } else if (this.addHealPhase) {
- this.scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
- this.scene.unshiftPhase(new SelectModifierPhase(this.scene, 0, null, { fillRemaining: false, rerollMultiplier: 0}));
- }
- }, this.scene.currentBattle.waveIndex * 1000);
-
- this.scene.pushPhase(new PostMysteryEncounterPhase(this.scene));
- this.end();
- }
-}
-
-/**
- * Will handle (in order):
- * - onPostOptionSelect logic (based on an option that was selected)
- * - Showing any outro dialogue messages
- * - Cleanup of any leftover intro visuals
- * - Queuing of the next wave
- */
-export class PostMysteryEncounterPhase extends Phase {
- onPostOptionSelect: (scene: BattleScene) => Promise;
-
- constructor(scene: BattleScene) {
- super(scene);
- this.onPostOptionSelect = this.scene.currentBattle.mysteryEncounter.selectedOption.onPostOptionPhase;
- }
-
- start() {
- super.start();
-
- if (this.onPostOptionSelect) {
- this.scene.executeWithSeedOffset(async () => {
- return await this.onPostOptionSelect(this.scene)
- .then((result) => {
- if (isNullOrUndefined(result) || result) {
- this.continueEncounter();
- }
- });
- }, this.scene.currentBattle.waveIndex * 1000);
- } else {
- this.continueEncounter();
- }
- }
-
- continueEncounter() {
- const endPhase = () => {
- this.scene.pushPhase(new NewBattlePhase(this.scene));
- this.end();
- };
-
- const outroDialogue = this.scene.currentBattle?.mysteryEncounter?.dialogue?.outro;
- if (outroDialogue?.length > 0) {
- let i = 0;
- const showNextDialogue = () => {
- const nextAction = i === outroDialogue.length - 1 ? endPhase : showNextDialogue;
- const dialogue = outroDialogue[i];
- let title: string = null;
- const text: string = getTextWithEncounterDialogueTokens(this.scene, dialogue.text);
- if (dialogue.speaker) {
- title = getTextWithEncounterDialogueTokens(this.scene, dialogue.speaker);
- }
-
- this.scene.ui.setMode(Mode.MESSAGE);
- if (title) {
- this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 0 ? 750 : 0);
- } else {
- this.scene.ui.showText(text, null, nextAction, i === 0 ? 750 : 0, true);
- }
- i++;
- };
-
- showNextDialogue();
- } else {
- endPhase();
- }
- }
-}
diff --git a/src/phases/select-modifier-phase.ts b/src/phases/select-modifier-phase.ts
deleted file mode 100644
index 5e53281ba841..000000000000
--- a/src/phases/select-modifier-phase.ts
+++ /dev/null
@@ -1,259 +0,0 @@
-import {ModifierTier} from "#app/modifier/modifier-tier";
-import {
- CustomModifierSettings,
- FusePokemonModifierType, getPlayerModifierTypeOptions,
- getPlayerShopModifierTypeOptionsForWave, ModifierPoolType,
- ModifierType,
- ModifierTypeOption,
- PokemonModifierType,
- PokemonMoveModifierType,
- PokemonPpRestoreModifierType,
- PokemonPpUpModifierType,
- regenerateModifierPoolThresholds,
- RememberMoveModifierType,
- TmModifierType
-} from "#app/modifier/modifier-type";
-import BattleScene from "#app/battle-scene";
-import * as Utils from "#app/utils";
-import {ExtraModifierModifier, Modifier, PokemonHeldItemModifier} from "#app/modifier/modifier";
-import i18next from "#app/plugins/i18n";
-import {Mode} from "#app/ui/ui";
-import PartyUiHandler, {PartyOption, PartyUiMode} from "#app/ui/party-ui-handler";
-import ModifierSelectUiHandler, {SHOP_OPTIONS_ROW_LIMIT} from "#app/ui/modifier-select-ui-handler";
-import {BattlePhase} from "#app/phases/battle-phase";
-import {isNullOrUndefined} from "#app/utils";
-
-export class SelectModifierPhase extends BattlePhase {
- private rerollCount: integer;
- private modifierTiers: ModifierTier[];
- private customModifierSettings: CustomModifierSettings;
-
- constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[], customModifierSettings?: CustomModifierSettings) {
- super(scene);
-
- this.rerollCount = rerollCount;
- this.modifierTiers = modifierTiers;
- this.customModifierSettings = customModifierSettings;
- }
-
- start() {
- super.start();
-
- if (!this.rerollCount) {
- this.updateSeed();
- } else {
- this.scene.reroll = false;
- }
-
- const party = this.scene.getParty();
- regenerateModifierPoolThresholds(party, this.getPoolType(), this.rerollCount);
- const modifierCount = new Utils.IntegerHolder(3);
- if (this.isPlayer()) {
- this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount);
- }
-
- // If custom modifiers are specified, overrides default item count
- if (!!this.customModifierSettings) {
- const newItemCount = (this.customModifierSettings.guaranteedModifierTiers?.length || 0) +
- (this.customModifierSettings.guaranteedModifierTypeOptions?.length || 0) +
- (this.customModifierSettings.guaranteedModifierTypeFuncs?.length || 0);
- if (this.customModifierSettings.fillRemaining) {
- const originalCount = modifierCount.value;
- modifierCount.value = originalCount > newItemCount ? originalCount : newItemCount;
- } else {
- modifierCount.value = newItemCount;
- }
- }
-
- const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value);
-
- const modifierSelectCallback = (rowCursor: integer, cursor: integer) => {
- if (rowCursor < 0 || cursor < 0) {
- this.scene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => {
- this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
- this.scene.ui.revertMode();
- this.scene.ui.setMode(Mode.MESSAGE);
- super.end();
- }, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)));
- });
- return false;
- }
- let modifierType: ModifierType;
- let cost: integer;
- switch (rowCursor) {
- case 0:
- switch (cursor) {
- case 0:
- const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers);
- if (rerollCost === 0 || this.scene.money < rerollCost) {
- this.scene.ui.playError();
- return false;
- } else {
- this.scene.reroll = true;
- this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type.tier)));
- this.scene.ui.clearText();
- this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
- this.scene.money -= rerollCost;
- this.scene.updateMoneyText();
- this.scene.animateMoneyChanged(false);
- this.scene.playSound("buy");
- }
- break;
- case 1:
- this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => {
- if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) {
- const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
- && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[];
- const itemModifier = itemModifiers[itemIndex];
- this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity);
- } else {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- }
- }, PartyUiHandler.FilterItemMaxStacks);
- break;
- case 2:
- this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- });
- break;
- case 3:
- this.scene.lockModifierTiers = !this.scene.lockModifierTiers;
- const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
- uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- uiHandler.updateLockRaritiesText();
- uiHandler.updateRerollCostText();
- return false;
- }
- return true;
- case 1:
- if (typeOptions.length === 0) {
- this.scene.ui.revertMode();
- this.scene.ui.setMode(Mode.MESSAGE);
- super.end();
- }
- modifierType = typeOptions[cursor].type;
- break;
- default:
- const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1));
- const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT];
- modifierType = shopOption.type;
- cost = shopOption.cost;
- break;
- }
-
- if (cost && this.scene.money < cost) {
- this.scene.ui.playError();
- return false;
- }
-
- const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
- const result = this.scene.addModifier(modifier, false, playSound);
- if (cost) {
- result.then(success => {
- if (success) {
- this.scene.money -= cost;
- this.scene.updateMoneyText();
- this.scene.animateMoneyChanged(false);
- this.scene.playSound("buy");
- (this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
- } else {
- this.scene.ui.playError();
- }
- });
- } else {
- const doEnd = () => {
- this.scene.ui.clearText();
- this.scene.ui.setMode(Mode.MESSAGE);
- super.end();
- };
- if (result instanceof Promise) {
- result.then(() => doEnd());
- } else {
- doEnd();
- }
- }
- };
-
- if (modifierType instanceof PokemonModifierType) {
- if (modifierType instanceof FusePokemonModifierType) {
- this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => {
- if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
- const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex]);
- applyModifier(modifier, true);
- });
- } else {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- }
- }, modifierType.selectFilter);
- } else {
- const pokemonModifierType = modifierType as PokemonModifierType;
- const isMoveModifier = modifierType instanceof PokemonMoveModifierType;
- const isTmModifier = modifierType instanceof TmModifierType;
- const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType;
- const isPpRestoreModifier = (modifierType instanceof PokemonPpRestoreModifierType || modifierType instanceof PokemonPpUpModifierType);
- const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER
- : isTmModifier ? PartyUiMode.TM_MODIFIER
- : isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER
- : PartyUiMode.MODIFIER;
- const tmMoveId = isTmModifier
- ? (modifierType as TmModifierType).moveId
- : undefined;
- this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => {
- if (slotIndex < 6) {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
- const modifier = !isMoveModifier
- ? !isRememberMoveModifier
- ? modifierType.newModifier(party[slotIndex])
- : modifierType.newModifier(party[slotIndex], option as integer)
- : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1);
- applyModifier(modifier, true);
- });
- } else {
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- }
- }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier);
- }
- } else {
- applyModifier(modifierType.newModifier());
- }
-
- return !cost;
- };
- this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
- }
-
- updateSeed(): void {
- this.scene.resetSeed();
- }
-
- isPlayer(): boolean {
- return true;
- }
-
- getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): integer {
- let baseValue = 0;
- if (lockRarities) {
- const tierValues = [50, 125, 300, 750, 2000];
- for (const opt of typeOptions) {
- baseValue += tierValues[opt.type.tier];
- }
- } else {
- baseValue = 250;
- }
- const multiplier = !isNullOrUndefined(this.customModifierSettings?.rerollMultiplier) ? this.customModifierSettings.rerollMultiplier : 1;
- return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount) * multiplier, Number.MAX_SAFE_INTEGER);
- }
-
- getPoolType(): ModifierPoolType {
- return ModifierPoolType.PLAYER;
- }
-
- getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] {
- return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined, this.customModifierSettings);
- }
-
- addModifier(modifier: Modifier): Promise {
- return this.scene.addModifier(modifier, false, true);
- }
-}
diff --git a/src/pipelines/sprite.ts b/src/pipelines/sprite.ts
index a61d321c765b..741c31183d42 100644
--- a/src/pipelines/sprite.ts
+++ b/src/pipelines/sprite.ts
@@ -4,7 +4,6 @@ import Pokemon from "../field/pokemon";
import Trainer from "../field/trainer";
import FieldSpritePipeline from "./field-sprite";
import * as Utils from "../utils";
-import MysteryEncounterIntroVisuals from "../field/mystery-encounter-intro";
const spriteFragShader = `
#ifdef GL_FRAGMENT_PRECISION_HIGH
@@ -354,7 +353,7 @@ export default class SpritePipeline extends FieldSpritePipeline {
const ignoreFieldPos = data["ignoreFieldPos"] as boolean;
const ignoreOverride = data["ignoreOverride"] as boolean;
- const isEntityObj = sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer || sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
+ const isEntityObj = sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer;
const field = isEntityObj ? sprite.parentContainer.parentContainer : sprite.parentContainer;
const position = isEntityObj
? [ sprite.parentContainer.x, sprite.parentContainer.y ]
@@ -449,7 +448,7 @@ export default class SpritePipeline extends FieldSpritePipeline {
const hasShadow = sprite.pipelineData["hasShadow"] as boolean;
if (hasShadow) {
- const isEntityObj = sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer || sprite.parentContainer instanceof MysteryEncounterIntroVisuals;
+ const isEntityObj = sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer;
const field = isEntityObj ? sprite.parentContainer.parentContainer : sprite.parentContainer;
const fieldScaleRatio = field.scale / 6;
const baseY = (isEntityObj
diff --git a/src/system/game-data.ts b/src/system/game-data.ts
index 6fd6afef4d32..f260f6263240 100644
--- a/src/system/game-data.ts
+++ b/src/system/game-data.ts
@@ -40,8 +40,6 @@ import { GameDataType } from "#enums/game-data-type";
import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
-import { MysteryEncounterFlags } from "../data/mystery-encounter-flags";
-import MysteryEncounter from "../data/mystery-encounter";
export const defaultStarterSpecies: Species[] = [
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
@@ -73,18 +71,20 @@ export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): str
return "tutorials";
case GameDataType.SEEN_DIALOGUES:
return "seenDialogues";
+ case GameDataType.RUN_HISTORY:
+ return "runHistory";
}
}
export function encrypt(data: string, bypassLogin: boolean): string {
return (bypassLogin
- ? (data: string) => btoa(encodeURIComponent(data))
+ ? (data: string) => btoa(data)
: (data: string) => AES.encrypt(data, saveKey))(data);
}
export function decrypt(data: string, bypassLogin: boolean): string {
return (bypassLogin
- ? (data: string) => decodeURIComponent(atob(data))
+ ? (data: string) => atob(data)
: (data: string) => AES.decrypt(data, saveKey).toString(enc.Utf8))(data);
}
@@ -95,6 +95,7 @@ interface SystemSaveData {
dexData: DexData;
starterData: StarterData;
gameStats: GameStats;
+ runHistory: RunHistoryData;
unlocks: Unlocks;
achvUnlocks: AchvUnlocks;
voucherUnlocks: VoucherUnlocks;
@@ -121,11 +122,18 @@ export interface SessionSaveData {
waveIndex: integer;
battleType: BattleType;
trainer: TrainerData;
- mysteryEncounter: MysteryEncounter;
gameVersion: string;
timestamp: integer;
challenges: ChallengeData[];
- mysteryEncounterFlags: MysteryEncounterFlags;
+}
+
+export interface RunHistoryData {
+ [key: integer]: RunEntries;
+}
+
+export interface RunEntries {
+ entry: SessionSaveData;
+ victory: boolean;
}
interface Unlocks {
@@ -287,7 +295,7 @@ export class GameData {
public starterData: StarterData;
public gameStats: GameStats;
-
+ public runHistory: RunHistoryData;
public unlocks: Unlocks;
public achvUnlocks: AchvUnlocks;
@@ -306,6 +314,7 @@ export class GameData {
this.trainerId = Utils.randInt(65536);
this.secretId = Utils.randInt(65536);
this.starterData = {};
+ this.runHistory = {};
this.gameStats = new GameStats();
this.unlocks = {
[Unlockables.ENDLESS_MODE]: false,
@@ -332,6 +341,7 @@ export class GameData {
trainerId: this.trainerId,
secretId: this.secretId,
gender: this.gender,
+ runHistory: this.runHistory,
dexData: this.dexData,
starterData: this.starterData,
gameStats: this.gameStats,
@@ -436,6 +446,11 @@ export class GameData {
localStorage.setItem(`data_${loggedInUser.username}`, encrypt(systemDataStr, bypassLogin));
+ if (!localStorage.hasOwnProperty(`runHistoryData_${loggedInUser.username}`)) {
+ localStorage.setItem(`runHistoryData_${loggedInUser.username}`, encrypt("", true));
+ }
+
+
/*const versions = [ this.scene.game.config.gameVersion, data.gameVersion || '0.0.0' ];
if (versions[0] !== versions[1]) {
@@ -840,9 +855,7 @@ export class GameData {
trainer: scene.currentBattle.battleType === BattleType.TRAINER ? new TrainerData(scene.currentBattle.trainer) : null,
gameVersion: scene.game.config.gameVersion,
timestamp: new Date().getTime(),
- challenges: scene.gameMode.challenges.map(c => new ChallengeData(c)),
- mysteryEncounter: scene.currentBattle.mysteryEncounter,
- mysteryEncounterFlags: scene.mysteryEncounterFlags
+ challenges: scene.gameMode.challenges.map(c => new ChallengeData(c))
} as SessionSaveData;
}
@@ -933,14 +946,11 @@ export class GameData {
scene.score = sessionData.score;
scene.updateScoreText();
- scene.mysteryEncounterFlags = sessionData?.mysteryEncounterFlags ? sessionData?.mysteryEncounterFlags : new MysteryEncounterFlags(null);
-
scene.newArena(sessionData.arena.biome);
const battleType = sessionData.battleType || 0;
const trainerConfig = sessionData.trainer ? trainerConfigs[sessionData.trainer.trainerType] : null;
- const mysteryEncounterConfig = sessionData?.mysteryEncounter;
- const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE : sessionData.enemyParty.length > 1, mysteryEncounterConfig);
+ const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE : sessionData.enemyParty.length > 1);
battle.enemyLevels = sessionData.enemyParty.map(p => p.level);
scene.arena.init();
@@ -1154,16 +1164,70 @@ export class GameData {
return ret;
}
- if (k === "mysteryEncounter") {
- return new MysteryEncounter(v);
- }
+ return v;
+ }) as SessionSaveData;
+ }
- if (k === "mysteryEncounterFlags") {
- return new MysteryEncounterFlags(v);
+ public async getRunHistoryData(scene: BattleScene): Promise {
+ if (!Utils.isLocal) {
+ const response = await Utils.apiFetch("savedata/runHistory", true);
+ const data = await response.json();
+ if (localStorage.hasOwnProperty(`runHistoryData_${loggedInUser.username}`)) {
+ let cachedResponse = localStorage.getItem(`runHistoryData_${loggedInUser.username}`);
+ if (cachedResponse) {
+ cachedResponse = JSON.parse(decrypt(cachedResponse, true));
+ }
+ const cachedRHData = cachedResponse ?? {};
+ //check to see whether cachedData or serverData is more up-to-date
+ if ( Object.keys(cachedRHData).length >= Object.keys(data).length ) {
+ return cachedRHData;
+ }
+ } else {
+ localStorage.setItem(`runHistoryData_${loggedInUser.username}`, JSON.parse(encrypt("", true)));
+ return {};
}
+ return data;
+ } else {
+ let cachedResponse = localStorage.getItem(`runHistoryData_${loggedInUser.username}`);
+ if (cachedResponse) {
+ cachedResponse = JSON.parse(decrypt(cachedResponse, true));
+ }
+ const cachedRHData = cachedResponse ?? {};
+ return cachedRHData;
+ }
+ }
- return v;
- }) as SessionSaveData;
+ async saveRunHistory(scene: BattleScene, runEntry : SessionSaveData, victory: boolean): Promise {
+
+ let runHistoryData = await this.getRunHistoryData(scene);
+ if (!runHistoryData) {
+ runHistoryData = {};
+ }
+ const timestamps = Object.keys(runHistoryData);
+ const timestampsNo = timestamps.map(Number);
+
+ //Arbitrary limit of 25 entries per User --> Can increase or decrease
+ if (timestamps.length >= 25) {
+ const oldestTimestamp = Math.min.apply(Math, timestampsNo);
+ delete this.scene.gameData.runHistory[oldestTimestamp.toString()];
+ }
+
+ const timestamp = (runEntry.timestamp).toString();
+ runHistoryData[timestamp] = {};
+ runHistoryData[timestamp]["entry"] = runEntry;
+ runHistoryData[timestamp]["victory"] = victory;
+
+ localStorage.setItem(`runHistoryData_${loggedInUser.username}`, encrypt(JSON.stringify(runHistoryData), true));
+
+ if (!Utils.isLocal) {
+ try {
+ Utils.apiPost("savedata/runHistory", JSON.stringify(runHistoryData), undefined, true);
+ return true;
+ } catch (err) {
+ console.log("savedata/runHistory POST failed : ", err);
+ return false;
+ }
+ }
}
saveAll(scene: BattleScene, skipVerification: boolean = false, sync: boolean = false, useCachedSession: boolean = false, useCachedSystem: boolean = false): Promise {
diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts
index 836d0ee84604..b09de0952595 100644
--- a/src/system/settings/settings.ts
+++ b/src/system/settings/settings.ts
@@ -16,13 +16,6 @@ const VOLUME_OPTIONS: SettingOption[] = new Array(11).fill(null).map((_, i) => i
value: "Mute",
label: i18next.t("settings:mute")
});
-const SHOP_OVERLAY_OPACITY_OPTIONS: SettingOption[] = new Array(9).fill(null).map((_, i) => {
- const value = ((i + 1) * 10).toString();
- return {
- value,
- label: value,
- };
-});
const OFF_ON: SettingOption[] = [
{
value: "Off",
@@ -79,7 +72,6 @@ export const SettingKeys = {
Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES",
Battle_Style: "BATTLE_STYLE",
Enable_Retries: "ENABLE_RETRIES",
- Hide_IVs: "HIDE_IVS",
Tutorials: "TUTORIALS",
Touch_Controls: "TOUCH_CONTROLS",
Vibration: "VIBRATION",
@@ -106,7 +98,6 @@ export const SettingKeys = {
SE_Volume: "SE_VOLUME",
Music_Preference: "MUSIC_PREFERENCE",
Show_BGM_Bar: "SHOW_BGM_BAR",
- Shop_Overlay_Opacity: "SHOP_OVERLAY_OPACITY"
};
/**
@@ -251,13 +242,6 @@ export const Setting: Array = [
default: 0,
type: SettingType.GENERAL
},
- {
- key: SettingKeys.Hide_IVs,
- label: i18next.t("settings:hideIvs"),
- options: OFF_ON,
- default: 0,
- type: SettingType.GENERAL
- },
{
key: SettingKeys.Tutorials,
label: i18next.t("settings:tutorials"),
@@ -551,14 +535,7 @@ export const Setting: Array = [
type: SettingType.AUDIO,
requireReload: true
},
- {
- key: SettingKeys.Shop_Overlay_Opacity,
- label: i18next.t("settings:shopOverlayOpacity"),
- options: SHOP_OVERLAY_OPACITY_OPTIONS,
- default: 7,
- type: SettingType.DISPLAY,
- requireReload: false
- },
+
];
/**
@@ -627,9 +604,6 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
case SettingKeys.Enable_Retries:
scene.enableRetries = Setting[index].options[value].value === "On";
break;
- case SettingKeys.Hide_IVs:
- scene.hideIvs = Setting[index].options[value].value === "On";
- break;
case SettingKeys.Skip_Seen_Dialogues:
scene.skipSeenDialogues = Setting[index].options[value].value === "On";
break;
@@ -786,9 +760,6 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
}
}
break;
- case SettingKeys.Shop_Overlay_Opacity:
- scene.updateShopOverlayOpacity(parseInt(Setting[index].options[value].value) * .01);
- break;
}
return true;
diff --git a/src/test/abilities/costar.test.ts b/src/test/abilities/costar.test.ts
index d5cd59fe0e6f..1b7eb3f7b90d 100644
--- a/src/test/abilities/costar.test.ts
+++ b/src/test/abilities/costar.test.ts
@@ -45,7 +45,7 @@ describe("Abilities - COSTAR", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.NASTY_PLOT));
await game.phaseInterceptor.to(CommandPhase);
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.toNextTurn();
expect(leftPokemon.summonData.battleStats[BattleStat.SPATK]).toBe(+2);
diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts
index 6fc46d55597a..297aa33e06c9 100644
--- a/src/test/abilities/disguise.test.ts
+++ b/src/test/abilities/disguise.test.ts
@@ -1,22 +1,19 @@
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
+import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
-import * as overrides from "#app/overrides";
+import * as Overrides from "#app/overrides";
import { Moves } from "#enums/moves";
import { Abilities } from "#enums/abilities";
import { Species } from "#enums/species";
-import { StatusEffect } from "#app/data/status-effect.js";
-import { MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases.js";
-import { BattlerTagType } from "#app/enums/battler-tag-type.js";
-import { BattleStat } from "#app/data/battle-stat.js";
+import { Status, StatusEffect } from "#app/data/status-effect.js";
+import { TurnEndPhase } from "#app/phases.js";
+import { QuietFormChangePhase } from "#app/form-change-phase.js";
const TIMEOUT = 20 * 1000;
-describe("Abilities - Disguise", () => {
+describe("Abilities - DISGUISE", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
- const bustedForm = 1;
- const disguisedForm = 0;
beforeAll(() => {
phaserGame = new Phaser.Game({
@@ -30,198 +27,72 @@ describe("Abilities - Disguise", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
- vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
-
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIMIKYU);
- vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DISGUISE);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
-
- vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.REGIELEKI);
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]);
- vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.UNNERVE);
- }, TIMEOUT);
-
- it("takes no damage from attacking move and transforms to Busted form, taking 1/8 max HP damage from the disguise breaking", async () => {
- await game.startBattle();
-
- const mimikyu = game.scene.getEnemyPokemon();
- const maxHp = mimikyu.getMaxHp();
- const disguiseDamage = Math.floor(maxHp / 8);
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK));
-
- await game.phaseInterceptor.to(MoveEndPhase);
-
- expect(mimikyu.hp).equals(maxHp - disguiseDamage);
- expect(mimikyu.formIndex).toBe(bustedForm);
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeUndefined();
- }, TIMEOUT);
-
- it("doesn't break disguise when attacked with ineffective move", async () => {
- await game.startBattle();
-
- const mimikyu = game.scene.getEnemyPokemon();
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.VACUUM_WAVE));
-
- await game.phaseInterceptor.to(MoveEndPhase);
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
- }, TIMEOUT);
-
- it("takes no damage from the first hit of a multihit move and transforms to Busted form, then takes damage from the second hit", async () => {
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SURGING_STRIKES]);
- vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(5);
- await game.startBattle();
-
- const mimikyu = game.scene.getEnemyPokemon();
- const maxHp = mimikyu.getMaxHp();
- const disguiseDamage = Math.floor(maxHp / 8);
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES));
-
- // First hit
- await game.phaseInterceptor.to(MoveEffectPhase);
- expect(mimikyu.hp).equals(maxHp - disguiseDamage);
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(mimikyu.getTag(BattlerTagType.ICE_FACE)).toBeUndefined();
-
- // Second hit
- await game.phaseInterceptor.to(MoveEffectPhase);
- expect(mimikyu.hp).lessThan(maxHp - disguiseDamage);
- expect(mimikyu.formIndex).toBe(bustedForm);
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeUndefined();
- }, TIMEOUT);
-
- it("takes effects from status moves and damage from status effects", async () => {
- await game.startBattle();
-
- const mimikyu = game.scene.getEnemyPokemon();
- expect(mimikyu.hp).toBe(mimikyu.getMaxHp());
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.TOXIC_THREAD));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(mimikyu.status.effect).toBe(StatusEffect.POISON);
- expect(mimikyu.summonData.battleStats[BattleStat.SPD]).toBe(-1);
- expect(mimikyu.hp).toBeLessThan(mimikyu.getMaxHp());
- }, TIMEOUT);
-
- it("persists form change when switched out", async () => {
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SHADOW_SNEAK, Moves.SHADOW_SNEAK, Moves.SHADOW_SNEAK, Moves.SHADOW_SNEAK]);
- vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(0);
- vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DISGUISE);
-
- await game.startBattle([Species.MIMIKYU, Species.FURRET]);
-
- let mimikyu = game.scene.getPlayerPokemon();
- const maxHp = mimikyu.getMaxHp();
- const disguiseDamage = Math.floor(maxHp / 8);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeUndefined();
- expect(mimikyu.formIndex).toBe(bustedForm);
- expect(mimikyu.hp).equals(maxHp - disguiseDamage);
-
- await game.toNextTurn();
- game.doSwitchPokemon(1);
-
- await game.phaseInterceptor.to(TurnEndPhase);
- mimikyu = game.scene.getParty()[1];
-
- expect(mimikyu.formIndex).toBe(bustedForm);
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeUndefined();
- }, TIMEOUT);
-
- it("reverts to Disguised on arena reset", async () => {
- vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
- vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(4);
- vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(0);
- vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DISGUISE);
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
- vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.BALL_FETCH);
- vi.spyOn(overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
- [Species.MIMIKYU]: bustedForm,
- });
-
- await game.startBattle([Species.MIMIKYU]);
-
- const mimikyu = game.scene.getPlayerPokemon();
-
- expect(mimikyu.formIndex).toBe(bustedForm);
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeUndefined();
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM));
- await game.doKillOpponents();
- await game.phaseInterceptor.to(TurnEndPhase);
- game.doSelectModifier();
- await game.phaseInterceptor.to(TurnInitPhase);
-
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- }, TIMEOUT);
-
- it("cannot be suppressed", async () => {
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.GASTRO_ACID]);
-
- await game.startBattle();
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.GASTRO_ACID));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- const mimikyu = game.scene.getEnemyPokemon();
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(mimikyu.summonData.abilitySuppressed).toBe(false);
- }, TIMEOUT);
-
- it("cannot be swapped with another ability", async () => {
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SKILL_SWAP]);
-
- await game.startBattle();
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SKILL_SWAP));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- const mimikyu = game.scene.getEnemyPokemon();
-
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(mimikyu.hasAbility(Abilities.DISGUISE)).toBe(true);
- }, TIMEOUT);
-
- it("cannot be copied", async () => {
- vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.TRACE);
-
- await game.startBattle();
-
- const mimikyu = game.scene.getEnemyPokemon();
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SIMPLE_BEAM));
-
- await game.phaseInterceptor.to(TurnInitPhase);
+ const moveToUse = Moves.SPLASH;
+ vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
+ vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.DISGUISE);
+ vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
+ vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
+ });
- expect(mimikyu.getTag(BattlerTagType.DISGUISE)).toBeDefined();
- expect(mimikyu.formIndex).toBe(disguisedForm);
- expect(game.scene.getPlayerPokemon().hasAbility(Abilities.TRACE)).toBe(true);
- }, TIMEOUT);
+ test(
+ "check if fainted pokemon switched to base form on arena reset",
+ async () => {
+ const baseForm = 0,
+ bustedForm = 1;
+ vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(4);
+ vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
+ [Species.MIMIKYU]: bustedForm,
+ });
+
+ await game.startBattle([Species.MAGIKARP, Species.MIMIKYU]);
+
+ const mimikyu = game.scene.getParty().find((p) => p.species.speciesId === Species.MIMIKYU);
+ expect(mimikyu).not.toBe(undefined);
+ expect(mimikyu.formIndex).toBe(bustedForm);
+
+ mimikyu.hp = 0;
+ mimikyu.status = new Status(StatusEffect.FAINT);
+ expect(mimikyu.isFainted()).toBe(true);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ await game.doKillOpponents();
+ await game.phaseInterceptor.to(TurnEndPhase);
+ game.doSelectModifier();
+ await game.phaseInterceptor.to(QuietFormChangePhase);
+
+ expect(mimikyu.formIndex).toBe(baseForm);
+ },
+ TIMEOUT
+ );
+
+ test(
+ "damage taken should be equal to 1/8 of its maximum HP, rounded down",
+ async () => {
+ const baseForm = 0,
+ bustedForm = 1;
+
+ vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.DARK_PULSE, Moves.DARK_PULSE, Moves.DARK_PULSE, Moves.DARK_PULSE]);
+ vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(20);
+ vi.spyOn(Overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(20);
+ vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
+ vi.spyOn(Overrides, "STARTER_FORM_OVERRIDES", "get").mockReturnValue({
+ [Species.MIMIKYU]: baseForm,
+ });
+
+ await game.startBattle([Species.MIMIKYU]);
+
+ const mimikyu = game.scene.getPlayerPokemon();
+ const damage = (Math.floor(mimikyu.getMaxHp()/8));
+
+ expect(mimikyu).not.toBe(undefined);
+ expect(mimikyu.formIndex).toBe(baseForm);
+
+ game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
+ await game.phaseInterceptor.to(TurnEndPhase);
+
+ expect(mimikyu.formIndex).toBe(bustedForm);
+ expect(game.scene.getEnemyPokemon().turnData.currDamageDealt).toBe(damage);
+ },
+ TIMEOUT
+ );
});
diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts
deleted file mode 100644
index ff579f87df02..000000000000
--- a/src/test/abilities/pastel_veil.test.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import * as overrides from "#app/overrides";
-import { Species } from "#enums/species";
-import {
- CommandPhase,
- TurnEndPhase,
-} from "#app/phases";
-import { Moves } from "#enums/moves";
-import { getMovePosition } from "#app/test/utils/gameManagerUtils";
-import { StatusEffect } from "#app/data/status-effect.js";
-import { allAbilities } from "#app/data/ability.js";
-import { Abilities } from "#app/enums/abilities.js";
-
-describe("Abilities - Pastel Veil", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH]);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD, Moves.TOXIC_THREAD]);
- });
-
- it("prevents the user and its allies from being afflicted by poison", async () => {
- await game.startBattle([Species.GALAR_PONYTA, Species.MAGIKARP]);
- const ponyta = game.scene.getPlayerField()[0];
-
- vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]);
-
- expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
- });
-
- it("it heals the poisoned status condition of allies if user is sent out into battle", async () => {
- await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.GALAR_PONYTA]);
- const ponyta = game.scene.getParty().find(p => p.species.speciesId === Species.GALAR_PONYTA);
-
- vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]);
-
- expect(ponyta.hasAbility(Abilities.PASTEL_VEIL)).toBe(true);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
-
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(game.scene.getPlayerField().some(p => p.status?.effect === StatusEffect.POISON)).toBe(true);
-
- await game.phaseInterceptor.to(CommandPhase);
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doSwitchPokemon(2);
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
- });
-});
diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts
deleted file mode 100644
index b705072dcbe5..000000000000
--- a/src/test/abilities/sweet_veil.test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import * as overrides from "#app/overrides";
-import { Species } from "#enums/species";
-import {
- CommandPhase,
- MoveEffectPhase,
- MovePhase,
- TurnEndPhase,
-} from "#app/phases";
-import { Moves } from "#enums/moves";
-import { getMovePosition } from "#app/test/utils/gameManagerUtils";
-import { BattlerTagType } from "#app/enums/battler-tag-type.js";
-
-describe("Abilities - Sweet Veil", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.REST]);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.POWDER, Moves.POWDER, Moves.POWDER, Moves.POWDER]);
- });
-
- it("prevents the user and its allies from falling asleep", async () => {
- await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
- });
-
- it("causes Rest to fail when used by the user or its allies", async () => {
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
- await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.REST));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
- });
-
- it("causes Yawn to fail if used on the user or its allies", async () => {
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.YAWN, Moves.YAWN, Moves.YAWN, Moves.YAWN]);
- await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(false);
- });
-
- it("prevents the user and its allies already drowsy due to Yawn from falling asleep.", async () => {
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.PIKACHU);
- vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(5);
- vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(5);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.YAWN, Moves.YAWN, Moves.YAWN, Moves.YAWN]);
-
- await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
-
- // First pokemon move
- await game.phaseInterceptor.to(MoveEffectPhase, false);
- vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true);
-
- // Second pokemon move
- await game.phaseInterceptor.to(MovePhase, false);
- await game.phaseInterceptor.to(MoveEffectPhase, false);
- vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true);
-
- expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true);
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- const drowsyMon = game.scene.getPlayerField().filter(p => !!p.getTag(BattlerTagType.DROWSY))[0];
-
- await game.phaseInterceptor.to(CommandPhase);
- game.doAttack(getMovePosition(game.scene, drowsyMon.getFieldIndex(), Moves.SPLASH));
- game.doSwitchPokemon(2);
-
- await game.phaseInterceptor.to(TurnEndPhase);
-
- expect(game.scene.getPlayerField().every(p => p.status?.effect)).toBe(false);
- });
-});
diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts
index fb498fe2b1d8..87949be70a8d 100644
--- a/src/test/battle/battle.test.ts
+++ b/src/test/battle/battle.test.ts
@@ -10,6 +10,7 @@ import {
EnemyCommandPhase,
LoginPhase,
SelectGenderPhase,
+ SelectModifierPhase,
SelectStarterPhase,
SummonPhase,
TitlePhase,
@@ -23,7 +24,6 @@ import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
describe("Test Battle Phase", () => {
let phaserGame: Phaser.Game;
diff --git a/src/test/evolutions/evolutions.test.ts b/src/test/evolutions/evolutions.test.ts
deleted file mode 100644
index 4e38e72bb7c9..000000000000
--- a/src/test/evolutions/evolutions.test.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import { Species } from "#enums/species";
-import * as Utils from "#app/utils";
-
-describe("Evolution tests", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- });
-
- it("tandemaus evolution form test", async () => {
- /* this test checks to make sure that tandemaus will
- * evolve into a 3 family maushold 25% of the time
- * and a 4 family maushold the other 75% of the time
- * This is done by using the getEvolution method in pokemon.ts
- * getEvolution will give back the form that the pokemon can evolve into
- * It does this by checking the pokemon conditions in pokemon-forms.ts
- * For tandemaus, the conditions are random due to a randSeedInt(4)
- * If the value is 0, it's a 3 family maushold, whereas if the value is
- * 1, 2 or 3, it's a 4 family maushold
- */
- await game.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus
- const playerPokemon = game.scene.getPlayerPokemon();
- playerPokemon.level = 25; // tandemaus evolves at level 25
- vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold
- const threeForm = playerPokemon.getEvolution();
- expect(threeForm.evoFormKey).toBe("three"); // as per pokemon-forms, the evoFormKey for 3 family mausholds is "three"
- for (let f = 1; f < 4; f++) {
- vi.spyOn(Utils, "randSeedInt").mockReturnValue(f); // setting the random generator to 1, 2 and 3 to force 4 family mausholds
- const fourForm = playerPokemon.getEvolution();
- expect(fourForm.evoFormKey).toBe(null); // meanwhile, according to the pokemon-forms, the evoFormKey for a 4 family maushold is null
- }
- }, 5000);
-});
diff --git a/src/test/localization/terrain.test.ts b/src/test/localization/terrain.test.ts
deleted file mode 100644
index 89884290e001..000000000000
--- a/src/test/localization/terrain.test.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-import { beforeAll, describe, beforeEach, afterEach, expect, it, vi } from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import * as overrides from "#app/overrides";
-import { Species } from "#enums/species";
-import { TerrainType, getTerrainName } from "#app/data/terrain";
-import { getTerrainStartMessage, getTerrainClearMessage, getTerrainBlockMessage } from "#app/data/weather";
-import i18next from "i18next";
-import { mockI18next } from "../utils/testUtils";
-
-describe("terrain", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- i18next.init();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
- });
-
- describe("NONE", () => {
- const terrainType = TerrainType.NONE;
-
- it("should return the obtain text", () => {
- mockI18next();
-
- const text = getTerrainName(terrainType);
- expect(text).toBe("");
- });
-
- it("should return the start text", () => {
- mockI18next();
-
- const text = getTerrainStartMessage(terrainType);
- expect(text).toBe(undefined);
- });
-
- it("should return the clear text", () => {
- mockI18next();
- const text = getTerrainClearMessage(terrainType);
- expect(text).toBe(undefined);
- });
-
- it("should return the block text", async () => {
- await game.startBattle([Species.MAGIKARP]);
- const pokemon = game.scene.getPlayerPokemon();
- mockI18next();
- const text = getTerrainBlockMessage(pokemon, terrainType);
- expect(text).toBe("terrain:defaultBlockMessage");
- });
- });
-
- describe("MISTY", () => {
- const terrainType = TerrainType.MISTY;
-
- it("should return the obtain text", () => {
- mockI18next();
-
- const text = getTerrainName(terrainType);
- expect(text).toBe("terrain:misty");
- });
-
- it("should return the start text", () => {
- mockI18next();
-
- const text = getTerrainStartMessage(terrainType);
- expect(text).toBe("terrain:mistyStartMessage");
- });
-
- it("should return the clear text", () => {
- mockI18next();
- const text = getTerrainClearMessage(terrainType);
- expect(text).toBe("terrain:mistyClearMessage");
- });
-
- it("should return the block text", async () => {
- await game.startBattle([Species.MAGIKARP]);
- const pokemon = game.scene.getPlayerPokemon();
- mockI18next();
- const text = getTerrainBlockMessage(pokemon, terrainType);
- expect(text).toBe("terrain:mistyBlockMessage");
- });
- });
-
- describe("ELECTRIC", () => {
- const terrainType = TerrainType.ELECTRIC;
-
- it("should return the obtain text", () => {
- mockI18next();
-
- const text = getTerrainName(terrainType);
- expect(text).toBe("terrain:electric");
- });
-
- it("should return the start text", () => {
- mockI18next();
-
- const text = getTerrainStartMessage(terrainType);
- expect(text).toBe("terrain:electricStartMessage");
- });
-
- it("should return the clear text", () => {
- mockI18next();
- const text = getTerrainClearMessage(terrainType);
- expect(text).toBe("terrain:electricClearMessage");
- });
-
- it("should return the block text", async () => {
- await game.startBattle([Species.MAGIKARP]);
- const pokemon = game.scene.getPlayerPokemon();
- mockI18next();
- const text = getTerrainBlockMessage(pokemon, terrainType);
- expect(text).toBe("terrain:defaultBlockMessage");
- });
- });
-
- describe("GRASSY", () => {
- const terrainType = TerrainType.GRASSY;
-
- it("should return the obtain text", () => {
- mockI18next();
-
- const text = getTerrainName(terrainType);
- expect(text).toBe("terrain:grassy");
- });
-
- it("should return the start text", () => {
- mockI18next();
-
- const text = getTerrainStartMessage(terrainType);
- expect(text).toBe("terrain:grassyStartMessage");
- });
-
- it("should return the clear text", () => {
- mockI18next();
- const text = getTerrainClearMessage(terrainType);
- expect(text).toBe("terrain:grassyClearMessage");
- });
-
- it("should return the block text", async () => {
- await game.startBattle([Species.MAGIKARP]);
- const pokemon = game.scene.getPlayerPokemon();
- mockI18next();
- const text = getTerrainBlockMessage(pokemon, terrainType);
- expect(text).toBe("terrain:defaultBlockMessage");
- });
- });
-
- describe("PSYCHIC", () => {
- const terrainType = TerrainType.PSYCHIC;
-
- it("should return the obtain text", () => {
- mockI18next();
-
- const text = getTerrainName(terrainType);
- expect(text).toBe("terrain:psychic");
- });
-
- it("should return the start text", () => {
- mockI18next();
-
- const text = getTerrainStartMessage(terrainType);
- expect(text).toBe("terrain:psychicStartMessage");
- });
-
- it("should return the clear text", () => {
- mockI18next();
- const text = getTerrainClearMessage(terrainType);
- expect(text).toBe("terrain:psychicClearMessage");
- });
-
- it("should return the block text", async () => {
- await game.startBattle([Species.MAGIKARP]);
- const pokemon = game.scene.getPlayerPokemon();
- mockI18next();
- const text = getTerrainBlockMessage(pokemon, terrainType);
- expect(text).toBe("terrain:defaultBlockMessage");
- });
- });
-
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- vi.resetAllMocks();
- });
-});
diff --git a/src/test/localization/battle-stat.test.ts b/src/test/lokalisation/battle-stat.test.ts
similarity index 100%
rename from src/test/localization/battle-stat.test.ts
rename to src/test/lokalisation/battle-stat.test.ts
diff --git a/src/test/localization/french.test.ts b/src/test/lokalisation/french.test.ts
similarity index 100%
rename from src/test/localization/french.test.ts
rename to src/test/lokalisation/french.test.ts
diff --git a/src/test/localization/status-effect.test.ts b/src/test/lokalisation/status-effect.test.ts
similarity index 100%
rename from src/test/localization/status-effect.test.ts
rename to src/test/lokalisation/status-effect.test.ts
diff --git a/src/test/moves/focus_punch.test.ts b/src/test/moves/focus_punch.test.ts
deleted file mode 100644
index 40975025d5a8..000000000000
--- a/src/test/moves/focus_punch.test.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import Phaser from "phaser";
-import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
-import GameManager from "../utils/gameManager";
-import * as Overrides from "#app/overrides";
-import { Species } from "#enums/species";
-import { Abilities } from "#enums/abilities";
-import { Moves } from "#enums/moves";
-import { getMovePosition } from "../utils/gameManagerUtils";
-import { BerryPhase, MessagePhase } from "#app/phases.js";
-import { StatusEffect } from "#app/data/status-effect.js";
-
-const TIMEOUT = 20 * 1000;
-
-describe("Moves - Focus Punch", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(Overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
- vi.spyOn(Overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.UNNERVE);
- vi.spyOn(Overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.FOCUS_PUNCH]);
- vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.GROUDON);
- vi.spyOn(Overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.INSOMNIA);
- vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]);
- vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
- vi.spyOn(Overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100);
- });
-
- test(
- "move should deal damage at the end of turn if uninterrupted",
- async () => {
- await game.startBattle([Species.CHARIZARD]);
-
- const leadPokemon = game.scene.getPlayerPokemon();
- expect(leadPokemon).not.toBe(undefined);
-
- const enemyPokemon = game.scene.getEnemyPokemon();
- expect(enemyPokemon).not.toBe(undefined);
-
- const enemyStartingHp = enemyPokemon.hp;
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH));
-
- await game.phaseInterceptor.to(MessagePhase);
-
- expect(enemyPokemon.hp).toBe(enemyStartingHp);
- expect(leadPokemon.getMoveHistory().length).toBe(0);
-
- await game.phaseInterceptor.to(BerryPhase, false);
-
- expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
- expect(leadPokemon.getMoveHistory().length).toBe(1);
- expect(leadPokemon.turnData.damageDealt).toBe(enemyStartingHp - enemyPokemon.hp);
- }, TIMEOUT
- );
-
- test(
- "move should fail if the user is hit",
- async () => {
- vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
-
- await game.startBattle([Species.CHARIZARD]);
-
- const leadPokemon = game.scene.getPlayerPokemon();
- expect(leadPokemon).not.toBe(undefined);
-
- const enemyPokemon = game.scene.getEnemyPokemon();
- expect(enemyPokemon).not.toBe(undefined);
-
- const enemyStartingHp = enemyPokemon.hp;
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH));
-
- await game.phaseInterceptor.to(MessagePhase);
-
- expect(enemyPokemon.hp).toBe(enemyStartingHp);
- expect(leadPokemon.getMoveHistory().length).toBe(0);
-
- await game.phaseInterceptor.to(BerryPhase, false);
-
- expect(enemyPokemon.hp).toBe(enemyStartingHp);
- expect(leadPokemon.getMoveHistory().length).toBe(1);
- expect(leadPokemon.turnData.damageDealt).toBe(0);
- }, TIMEOUT
- );
-
- test(
- "move should be cancelled if the user is asleep",
- async () => {
- vi.spyOn(Overrides, "STATUS_OVERRIDE", "get").mockReturnValue(StatusEffect.SLEEP);
-
- await game.startBattle([Species.CHARIZARD]);
-
- const leadPokemon = game.scene.getPlayerPokemon();
- expect(leadPokemon).not.toBe(undefined);
-
- const enemyPokemon = game.scene.getEnemyPokemon();
- expect(enemyPokemon).not.toBe(undefined);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH));
-
- await game.phaseInterceptor.to(MessagePhase);
-
- expect(leadPokemon.getMoveHistory().length).toBe(1);
-
- await game.phaseInterceptor.to(BerryPhase, false);
-
- expect(leadPokemon.getMoveHistory().length).toBe(1);
- expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
- }, TIMEOUT
- );
-
- test(
- "move should be cancelled if the user falls asleep mid-turn",
- async () => {
- vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPORE, Moves.SPORE, Moves.SPORE, Moves.SPORE]);
-
- await game.startBattle([Species.CHARIZARD]);
-
- const leadPokemon = game.scene.getPlayerPokemon();
- expect(leadPokemon).toBeDefined();
-
- const enemyPokemon = game.scene.getEnemyPokemon();
- expect(enemyPokemon).toBeDefined();
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH));
-
- await game.phaseInterceptor.to(MessagePhase); // Header message
-
- expect(leadPokemon.getMoveHistory().length).toBe(0);
-
- await game.phaseInterceptor.to(BerryPhase, false);
-
- expect(leadPokemon.getMoveHistory().length).toBe(1);
- expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
- }, TIMEOUT
- );
-});
diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts
deleted file mode 100644
index 173be77fadf1..000000000000
--- a/src/test/moves/glaive_rush.test.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import * as overrides from "#app/overrides";
-import { DamagePhase, TurnEndPhase } from "#app/phases";
-import { getMovePosition } from "#app/test/utils/gameManagerUtils";
-import { Moves } from "#enums/moves";
-import { Species } from "#enums/species";
-import { Abilities } from "#app/enums/abilities.js";
-import { allMoves } from "#app/data/move.js";
-
-
-describe("Moves - Glaive Rush", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
- vi.spyOn(overrides, "NEVER_CRIT_OVERRIDE", "get").mockReturnValue(true);
- vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MAGIKARP);
- vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.BALL_FETCH);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(Array(4).fill(Moves.GLAIVE_RUSH));
- vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.KLINK);
- vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.UNNERVE);
- vi.spyOn(overrides, "PASSIVE_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.FUR_COAT);
- vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SHADOW_SNEAK, Moves.AVALANCHE, Moves.SPLASH, Moves.GLAIVE_RUSH]);
- });
-
- it("takes double damage from attacks", async() => {
- await game.startBattle();
- const enemy = game.scene.getEnemyPokemon();
- enemy.hp = 1000;
-
- vi.spyOn(game.scene, "randBattleSeedInt").mockReturnValue(0);
- game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK));
- await game.phaseInterceptor.to(DamagePhase);
- const damageDealt = 1000 - enemy.hp;
- await game.phaseInterceptor.to(TurnEndPhase);
- game.doAttack(getMovePosition(game.scene, 0, Moves.SHADOW_SNEAK));
- await game.phaseInterceptor.to(DamagePhase);
- expect(enemy.hp).toBeLessThanOrEqual(1001 - (damageDealt * 3));
-
- }, 20000);
-
- it("always gets hit by attacks", async() => {
- await game.startBattle();
- const enemy = game.scene.getEnemyPokemon();
- enemy.hp = 1000;
-
- allMoves[Moves.AVALANCHE].accuracy = 0;
- game.doAttack(getMovePosition(game.scene, 0, Moves.AVALANCHE));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(enemy.hp).toBeLessThan(1000);
-
- }, 20000);
-
- it("interacts properly with multi-lens", async() => {
- vi.spyOn(overrides, "STARTING_HELD_ITEMS_OVERRIDE", "get").mockReturnValue([{name: "MULTI_LENS", count: 2}]);
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(Array(4).fill(Moves.AVALANCHE));
- await game.startBattle();
- const player = game.scene.getPlayerPokemon();
- const enemy = game.scene.getEnemyPokemon();
- enemy.hp = 1000;
- player.hp = 1000;
-
- allMoves[Moves.AVALANCHE].accuracy = 0;
- game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBeLessThan(1000);
- player.hp = 1000;
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBe(1000);
-
- }, 20000);
-
- it("secondary effects only last until next move", async() => {
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(Array(4).fill(Moves.SHADOW_SNEAK));
- await game.startBattle();
- const player = game.scene.getPlayerPokemon();
- const enemy = game.scene.getEnemyPokemon();
- enemy.hp = 1000;
- player.hp = 1000;
- allMoves[Moves.SHADOW_SNEAK].accuracy = 0;
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBe(1000);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- await game.phaseInterceptor.to(TurnEndPhase);
- const damagedHp = player.hp;
- expect(player.hp).toBeLessThan(1000);
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBe(damagedHp);
-
- }, 20000);
-
- it("secondary effects are removed upon switching", async() => {
- vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue(Array(4).fill(Moves.SHADOW_SNEAK));
- vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(0);
- await game.startBattle([Species.KLINK, Species.FEEBAS]);
- const player = game.scene.getPlayerPokemon();
- const enemy = game.scene.getEnemyPokemon();
- enemy.hp = 1000;
- allMoves[Moves.SHADOW_SNEAK].accuracy = 0;
-
- game.doAttack(getMovePosition(game.scene, 0, Moves.GLAIVE_RUSH));
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBe(player.getMaxHp());
-
- game.doSwitchPokemon(1);
- await game.phaseInterceptor.to(TurnEndPhase);
- game.doSwitchPokemon(1);
- await game.phaseInterceptor.to(TurnEndPhase);
- expect(player.hp).toBe(player.getMaxHp());
-
- }, 20000);
-});
diff --git a/src/test/mystery-encounter/mystery-encounter.test.ts b/src/test/mystery-encounter/mystery-encounter.test.ts
deleted file mode 100644
index b8f500700113..000000000000
--- a/src/test/mystery-encounter/mystery-encounter.test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {afterEach, beforeAll, beforeEach, describe, it, vi} from "vitest";
-import * as overrides from "../../overrides";
-import GameManager from "#app/test/utils/gameManager";
-import Phaser from "phaser";
-
-describe("Mystery Encounter", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- vi.spyOn(overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(64);
- vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
- });
-
- it("spawns a mystery encounter", async() => {
- // await game.runToSummon([
- // Species.CHARIZARD,
- // Species.VOLCARONA
- // ]);
- // expect(game.scene.getCurrentPhase().constructor.name).toBe(EncounterPhase.name);
- }, 100000);
-
- it("spawns mysterious challengers encounter", async() => {
- });
-
- it("spawns mysterious chest encounter", async() => {
- });
-
- it("spawns dark deal encounter", async() => {
- });
-
- it("spawns fight or flight encounter", async() => {
- });
-});
-
diff --git a/src/test/phases/select-modifier-phase.test.ts b/src/test/phases/select-modifier-phase.test.ts
deleted file mode 100644
index e58198da0cbe..000000000000
--- a/src/test/phases/select-modifier-phase.test.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
-import Phaser from "phaser";
-import GameManager from "#app/test/utils/gameManager";
-import {initSceneWithoutEncounterPhase} from "#app/test/utils/gameManagerUtils";
-import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
-import {ModifierTier} from "#app/modifier/modifier-tier";
-import * as Utils from "#app/utils";
-import {CustomModifierSettings, ModifierTypeOption, modifierTypes} from "#app/modifier/modifier-type";
-import BattleScene from "#app/battle-scene";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
-import {Species} from "#enums/species";
-import {Mode} from "#app/ui/ui";
-import {PlayerPokemon} from "#app/field/pokemon";
-import {getPokemonSpecies} from "#app/data/pokemon-species";
-
-describe("SelectModifierPhase", () => {
- let phaserGame: Phaser.Game;
- let game: GameManager;
- let scene: BattleScene;
-
- beforeAll(() => {
- phaserGame = new Phaser.Game({
- type: Phaser.HEADLESS,
- });
- });
-
- beforeEach(() => {
- game = new GameManager(phaserGame);
- scene = game.scene;
-
- vi.spyOn(scene, "resetSeed").mockImplementation(() => {
- scene.waveSeed = "test";
- Phaser.Math.RND.sow([ scene.waveSeed ]);
- scene.rngCounter = 0;
- });
-
- initSceneWithoutEncounterPhase(scene, [Species.ABRA, Species.VOLCARONA]);
- });
-
- afterEach(() => {
- game.phaseInterceptor.restoreOg();
-
- vi.clearAllMocks();
- });
-
- it("should start a select modifier phase", async () => {
- const selectModifierPhase = new SelectModifierPhase(scene);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- }, 20000);
-
- it("should generate random modifiers", async () => {
- const selectModifierPhase = new SelectModifierPhase(scene);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(3);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TEMP_STAT_BOOSTER");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("POKEBALL");
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("BERRY");
- }, 5000);
-
- it("should modify reroll cost", async () => {
- const options = [
- new ModifierTypeOption(modifierTypes.POTION(), 0, 100),
- new ModifierTypeOption(modifierTypes.ETHER(), 0, 400),
- new ModifierTypeOption(modifierTypes.REVIVE(), 0, 1000)
- ];
-
- const selectModifierPhase1 = new SelectModifierPhase(scene);
- const selectModifierPhase2 = new SelectModifierPhase(scene, 0, null, { rerollMultiplier: 2});
-
- const cost1 = selectModifierPhase1.getRerollCost(options, false);
- const cost2 = selectModifierPhase2.getRerollCost(options, false);
- expect(cost2).toEqual(cost1 * 2);
- }, 5000);
-
- it("should generate random modifiers from reroll", async () => {
- let selectModifierPhase = new SelectModifierPhase(scene);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(3);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TEMP_STAT_BOOSTER");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("POKEBALL");
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("BERRY");
-
- // Simulate selecting reroll
- selectModifierPhase = new SelectModifierPhase(scene, 1, [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.COMMON]);
- scene.unshiftPhase(selectModifierPhase);
- scene.ui.setMode(Mode.MESSAGE).then(() => game.endPhase());
- await game.phaseInterceptor.run(SelectModifierPhase);
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- expect(modifierSelectHandler.options.length).toEqual(3);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("TM_COMMON");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("LURE");
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("PP_UP");
- }, 5000);
-
- it("should generate random modifiers of same tier for reroll with reroll lock", async () => {
- // Just use fully random seed for this test
- vi.spyOn(scene, "resetSeed").mockImplementation(() => {
- scene.waveSeed = Utils.shiftCharCodes(scene.seed, 5);
- Phaser.Math.RND.sow([ scene.waveSeed ]);
- console.log("Wave Seed:", scene.waveSeed, 5);
- scene.rngCounter = 0;
- });
-
- let selectModifierPhase = new SelectModifierPhase(scene);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(3);
- const firstRollTiers: ModifierTier[] = modifierSelectHandler.options.map(o => o.modifierTypeOption.type.tier);
-
- // Simulate selecting reroll with lock
- scene.lockModifierTiers = true;
- scene.reroll = true;
- selectModifierPhase = new SelectModifierPhase(scene, 1, firstRollTiers);
- scene.unshiftPhase(selectModifierPhase);
- scene.ui.setMode(Mode.MESSAGE).then(() => game.endPhase());
- await game.phaseInterceptor.run(SelectModifierPhase);
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- expect(modifierSelectHandler.options.length).toEqual(3);
- // Reroll with lock can still upgrade
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.tier - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[0]);
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[1]);
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount).toEqual(firstRollTiers[2]);
- }, 5000);
-
- it("should generate custom modifiers", async () => {
- const customModifiers: CustomModifierSettings = {
- guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_ULTRA, modifierTypes.LEFTOVERS, modifierTypes.AMULET_COIN, modifierTypes.GOLDEN_PUNCH]
- };
- const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(5);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MEMORY_MUSHROOM");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("TM_ULTRA");
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.id).toEqual("LEFTOVERS");
- expect(modifierSelectHandler.options[3].modifierTypeOption.type.id).toEqual("AMULET_COIN");
- expect(modifierSelectHandler.options[4].modifierTypeOption.type.id).toEqual("GOLDEN_PUNCH");
- }, 5000);
-
- it("should generate custom modifier tiers that can upgrade from luck", async () => {
- const customModifiers: CustomModifierSettings = {
- guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.ULTRA, ModifierTier.ROGUE, ModifierTier.MASTER]
- };
- const pokemon = new PlayerPokemon(scene, getPokemonSpecies(Species.BULBASAUR), 10, undefined, 0, undefined, true, 2, undefined, undefined, undefined);
-
- // Fill party with max shinies
- while (scene.getParty().length > 0) {
- scene.getParty().pop();
- }
- scene.getParty().push(pokemon, pokemon, pokemon, pokemon, pokemon, pokemon);
-
- const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(5);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.tier - modifierSelectHandler.options[0].modifierTypeOption.upgradeCount).toEqual(ModifierTier.COMMON);
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier - modifierSelectHandler.options[1].modifierTypeOption.upgradeCount).toEqual(ModifierTier.GREAT);
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier - modifierSelectHandler.options[2].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ULTRA);
- expect(modifierSelectHandler.options[3].modifierTypeOption.type.tier - modifierSelectHandler.options[3].modifierTypeOption.upgradeCount).toEqual(ModifierTier.ROGUE);
- expect(modifierSelectHandler.options[4].modifierTypeOption.type.tier - modifierSelectHandler.options[4].modifierTypeOption.upgradeCount).toEqual(ModifierTier.MASTER);
- }, 5000);
-
- it("should generate custom modifiers and modifier tiers together", async () => {
- const customModifiers: CustomModifierSettings = {
- guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_COMMON],
- guaranteedModifierTiers: [ModifierTier.MASTER, ModifierTier.MASTER]
- };
- const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(4);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MEMORY_MUSHROOM");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.id).toEqual("TM_COMMON");
- expect(modifierSelectHandler.options[2].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER);
- expect(modifierSelectHandler.options[3].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER);
- }, 5000);
-
- it("should fill remaining modifiers if fillRemaining is true with custom modifiers", async () => {
- const customModifiers: CustomModifierSettings = {
- guaranteedModifierTypeFuncs: [modifierTypes.MEMORY_MUSHROOM],
- guaranteedModifierTiers: [ModifierTier.MASTER],
- fillRemaining: true
- };
- const selectModifierPhase = new SelectModifierPhase(scene, 0, null, customModifiers);
- scene.pushPhase(selectModifierPhase);
- await game.phaseInterceptor.run(SelectModifierPhase);
-
-
- expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
- const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
- expect(modifierSelectHandler.options.length).toEqual(3);
- expect(modifierSelectHandler.options[0].modifierTypeOption.type.id).toEqual("MEMORY_MUSHROOM");
- expect(modifierSelectHandler.options[1].modifierTypeOption.type.tier).toEqual(ModifierTier.MASTER);
- }, 5000);
-});
diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts
index 90a1eb242a11..336e5bccd260 100644
--- a/src/test/ui/transfer-item.test.ts
+++ b/src/test/ui/transfer-item.test.ts
@@ -5,6 +5,7 @@ import { Button } from "#app/enums/buttons";
import * as overrides from "#app/overrides";
import {
BattleEndPhase,
+ SelectModifierPhase
} from "#app/phases";
import GameManager from "#app/test/utils/gameManager";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
@@ -14,7 +15,6 @@ import Phaser from "phaser";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { getMovePosition } from "../utils/gameManagerUtils";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
describe("UI - Transfer Items", () => {
diff --git a/src/test/utils/gameManagerUtils.ts b/src/test/utils/gameManagerUtils.ts
index ab813d4dfa9a..db9ba7174a97 100644
--- a/src/test/utils/gameManagerUtils.ts
+++ b/src/test/utils/gameManagerUtils.ts
@@ -6,9 +6,6 @@ import {Starter} from "#app/ui/starter-select-ui-handler";
import {GameModes, getGameMode} from "#app/game-mode";
import {getPokemonSpecies, getPokemonSpeciesForm} from "#app/data/pokemon-species";
import {PlayerPokemon} from "#app/field/pokemon";
-import Battle, {BattleType} from "#app/battle";
-import { Moves } from "#app/enums/moves";
-import BattleScene from "#app/battle-scene";
export function blobToString(blob) {
return new Promise((resolve, reject) => {
@@ -82,30 +79,9 @@ export function waitUntil(truth) {
});
}
-/** Get the index of `move` from the moveset of the pokemon on the player's field at location `pokemonIndex` */
-export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: Moves) {
+export function getMovePosition(scene, pokemonIndex, moveIndex) {
const playerPokemon = scene.getPlayerField()[pokemonIndex];
const moveSet = playerPokemon.getMoveset();
- const index = moveSet.findIndex((m) => m.moveId === move);
+ const index = moveSet.findIndex((move) => move.moveId === moveIndex);
return index;
}
-
-/**
- * Useful for populating party, wave index, etc. without having to spin up and run through an entire EncounterPhase
- * @param scene
- * @param species
- */
-export function initSceneWithoutEncounterPhase(scene, species?: Species[]) {
- const starters = generateStarter(scene, species);
- starters.forEach((starter) => {
- const starterProps = scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
- const starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0));
- const starterGender = Gender.MALE;
- const starterIvs = scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
- const starterPokemon = scene.addPlayerPokemon(starter.species, scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature);
- starterPokemon.tryPopulateMoveset(starter.moveset);
- scene.getParty().push(starterPokemon);
- });
-
- scene.currentBattle = new Battle(getGameMode(GameModes.CLASSIC), 5, BattleType.WILD, null, false);
-}
diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts
index e99adce15505..e8cec7c9989d 100644
--- a/src/test/utils/phaseInterceptor.ts
+++ b/src/test/utils/phaseInterceptor.ts
@@ -17,6 +17,7 @@ import {
NextEncounterPhase,
PostSummonPhase,
SelectGenderPhase,
+ SelectModifierPhase,
SelectStarterPhase,
SelectTargetPhase,
ShinySparklePhase,
@@ -37,13 +38,6 @@ import UI, {Mode} from "#app/ui/ui";
import {Phase} from "#app/phase";
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
import {QuietFormChangePhase} from "#app/form-change-phase";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
-import {
- MysteryEncounterBattlePhase,
- MysteryEncounterOptionSelectedPhase,
- MysteryEncounterPhase,
- PostMysteryEncounterPhase
-} from "#app/phases/mystery-encounter-phase";
export default class PhaseInterceptor {
public scene;
@@ -98,14 +92,10 @@ export default class PhaseInterceptor {
[QuietFormChangePhase, this.startPhase],
[SwitchPhase, this.startPhase],
[SwitchSummonPhase, this.startPhase],
- [MysteryEncounterPhase, this.startPhase],
- [MysteryEncounterOptionSelectedPhase, this.startPhase],
- [MysteryEncounterBattlePhase, this.startPhase],
- [PostMysteryEncounterPhase, this.startPhase]
];
private endBySetMode = [
- TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase
+ TitlePhase, SelectGenderPhase, CommandPhase
];
/**
diff --git a/src/test/vitest.setup.ts b/src/test/vitest.setup.ts
index db9b75406c51..2caa82289d96 100644
--- a/src/test/vitest.setup.ts
+++ b/src/test/vitest.setup.ts
@@ -12,10 +12,8 @@ import { initSpecies } from "#app/data/pokemon-species";
import { initAchievements } from "#app/system/achv.js";
import { initVouchers } from "#app/system/voucher.js";
import { initStatsKeys } from "#app/ui/game-stats-ui-handler";
-import { beforeAll, beforeEach, vi } from "vitest";
-import * as overrides from "#app/overrides";
-import {initMysteryEncounterDialogue} from "#app/data/mystery-encounters/dialogue/mystery-encounter-dialogue";
-import {initMysteryEncounters} from "#app/data/mystery-encounters/mystery-encounters";
+
+import { beforeAll } from "vitest";
initVouchers();
initAchievements();
@@ -28,8 +26,6 @@ initSpecies();
initMoves();
initAbilities();
initLoggedInUser();
-initMysteryEncounterDialogue();
-initMysteryEncounters();
global.testFailed = false;
@@ -41,8 +37,3 @@ beforeAll(() => {
}
});
});
-
-// Disables Mystery Encounters on all tests (can be overridden at test level)
-beforeEach( () => {
- vi.spyOn(overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(0);
-});
diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts
index 459a7f4b1721..3b889228e277 100644
--- a/src/ui/battle-info.ts
+++ b/src/ui/battle-info.ts
@@ -12,9 +12,7 @@ import BattleFlyout from "./battle-flyout";
import { WindowVariant, addWindow } from "./ui-theme";
import i18next from "i18next";
-let battleStatOrder = [];
-const battleStatOrderPlayer = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD];
-const battleStatOrderEnemy = [BattleStat.HP, BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD];
+const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ];
export default class BattleInfo extends Phaser.GameObjects.Container {
private baseY: number;
@@ -224,44 +222,20 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.statValuesContainer = this.scene.add.container(0, 0);
this.statsContainer.add(this.statValuesContainer);
- // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy
- // since the player won't have HP to show, it doesn't need to change from the current version
- const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5;
- const paddingX = this.player ? 4 : 2;
- const statOverflow = this.player ? 1 : 0;
- battleStatOrder = this.player ? battleStatOrderPlayer : battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order
-
battleStatOrder.map((s, i) => {
- // we do a check for i > statOverflow to see when the stat labels go onto the next column
- // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0
- // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1
- const statX = i > statOverflow ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0
-
- const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis
- let statY: number; // this will be the y-axis placement for the labels
- if (battleStatOrder[i] === BattleStat.SPD || battleStatOrder[i] === BattleStat.HP) {
- statY = baseY + 5;
- } else {
- statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because battleStatOrder for enemies has HP, battleStatOrder[1]=ATK, but for players battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us
- }
-
+ const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8;
+ const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5);
const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]);
statLabel.setName("icon_stat_label_" + i.toString());
statLabel.setOrigin(0, 0);
statLabels.push(statLabel);
this.statValuesContainer.add(statLabel);
- const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", battleStatOrder[i] !== BattleStat.HP ? "3" : "empty");
+ const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3");
statNumber.setName("icon_stat_number_" + i.toString());
statNumber.setOrigin(0, 0);
this.statNumbers.push(statNumber);
this.statValuesContainer.add(statNumber);
-
- if (battleStatOrder[i] === BattleStat.HP) {
- statLabel.setVisible(false);
- statNumber.setVisible(false);
- }
-
});
if (!this.player) {
@@ -300,10 +274,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}
}
- getStatsValueContainer(): Phaser.GameObjects.Container {
- return this.statValuesContainer;
- }
-
initInfo(pokemon: Pokemon) {
this.updateNameText(pokemon);
const nameTextWidth = this.nameText.displayWidth;
@@ -425,7 +395,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.statValuesContainer.setPosition(8, 7);
}
- battleStatOrder = this.player ? battleStatOrderPlayer : battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order
const battleStats = battleStatOrder.map(() => 0);
this.lastBattleStats = battleStats.join("");
@@ -643,7 +612,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.lastLevel = pokemon.level;
}
- battleStatOrder = this.player ? battleStatOrderPlayer : battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order
const battleStats = pokemon.summonData
? pokemon.summonData.battleStats
: battleStatOrder.map(() => 0);
@@ -761,9 +729,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
updateBattleStats(battleStats: integer[]): void {
battleStatOrder.map((s, i) => {
- if (s !== BattleStat.HP) {
- this.statNumbers[i].setFrame(battleStats[s].toString());
- }
+ this.statNumbers[i].setFrame(battleStats[s].toString());
});
}
diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts
index 83ab9ad52fb2..f2da553c6da4 100644
--- a/src/ui/battle-message-ui-handler.ts
+++ b/src/ui/battle-message-ui-handler.ts
@@ -194,7 +194,24 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
this.scene.executeWithSeedOffset(() => {
let levelUpStatsValuesText = "";
const stats = Utils.getEnumValues(Stat);
- const shownStats = this.topIvs(ivs, shownIvsCount);
+ let shownStats: Stat[] = [];
+ if (shownIvsCount < 6) {
+ const statsPool = stats.slice(0);
+ for (let i = 0; i < shownIvsCount; i++) {
+ let shownStat: Stat;
+ let highestIv = -1;
+ statsPool.map(s => {
+ if (ivs[s] > highestIv) {
+ shownStat = s as Stat;
+ highestIv = ivs[s];
+ }
+ });
+ shownStats.push(shownStat);
+ statsPool.splice(statsPool.indexOf(shownStat), 1);
+ }
+ } else {
+ shownStats = stats;
+ }
for (const s of stats) {
levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s, pokemonId) : "???"}\n`;
}
@@ -210,29 +227,6 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
});
}
- topIvs(ivs: integer[], shownIvsCount: integer): Stat[] {
- const stats = Utils.getEnumValues(Stat);
- let shownStats: Stat[] = [];
- if (shownIvsCount < 6) {
- const statsPool = stats.slice(0);
- for (let i = 0; i < shownIvsCount; i++) {
- let shownStat: Stat;
- let highestIv = -1;
- statsPool.map(s => {
- if (ivs[s] > highestIv) {
- shownStat = s as Stat;
- highestIv = ivs[s];
- }
- });
- shownStats.push(shownStat);
- statsPool.splice(statsPool.indexOf(shownStat), 1);
- }
- } else {
- shownStats = stats;
- }
- return shownStats;
- }
-
getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string {
const starterSpecies = this.scene.getPokemonById(pokemonId).species.getRootSpeciesId(true);
const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs;
diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts
index b9f74045e102..ed5205124431 100644
--- a/src/ui/fight-ui-handler.ts
+++ b/src/ui/fight-ui-handler.ts
@@ -11,30 +11,6 @@ import i18next from "i18next";
import {Button} from "#enums/buttons";
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
-/**
- * Returns a specific move's color based on its type effectiveness against opponents
- * If there are multiple opponents, the highest effectiveness' color is returned
- * @returns A color or undefined if the default color should be used
- */
-export function getMoveColor(pokemon: Pokemon, pokemonMove: PokemonMove): string | undefined {
- if (!pokemon.scene.typeHints) {
- return undefined;
- }
-
- const opponents = pokemon.getOpponents();
- if (opponents.length <= 0) {
- return undefined;
- }
-
- const moveColors = opponents.map((opponent) => {
- return opponent.getMoveEffectiveness(pokemon, pokemonMove);
- }).sort((a, b) => b - a).map((effectiveness) => {
- return getTypeDamageMultiplierColor(effectiveness, "offense");
- });
-
- return moveColors[0];
-}
-
export default class FightUiHandler extends UiHandler {
private movesContainer: Phaser.GameObjects.Container;
private moveInfoContainer: Phaser.GameObjects.Container;
@@ -273,13 +249,37 @@ export default class FightUiHandler extends UiHandler {
const pokemonMove = moveset[moveIndex];
moveText.setText(pokemonMove.getName());
moveText.setName(pokemonMove.getName());
- moveText.setColor(getMoveColor(pokemon, pokemonMove) ?? moveText.style.color);
+ moveText.setColor(this.getMoveColor(pokemon, pokemonMove) ?? moveText.style.color);
}
this.movesContainer.add(moveText);
}
}
+ /**
+ * Returns a specific move's color based on its type effectiveness against opponents
+ * If there are multiple opponents, the highest effectiveness' color is returned
+ * @returns A color or undefined if the default color should be used
+ */
+ private getMoveColor(pokemon: Pokemon, pokemonMove: PokemonMove): string | undefined {
+ if (!this.scene.typeHints) {
+ return undefined;
+ }
+
+ const opponents = pokemon.getOpponents();
+ if (opponents.length <= 0) {
+ return undefined;
+ }
+
+ const moveColors = opponents.map((opponent) => {
+ return opponent.getMoveEffectiveness(pokemon, pokemonMove);
+ }).sort((a, b) => b - a).map((effectiveness) => {
+ return getTypeDamageMultiplierColor(effectiveness, "offense");
+ });
+
+ return moveColors[0];
+ }
+
clear() {
super.clear();
const messageHandler = this.getUi().getMessageHandler();
diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts
index 571a09f3b375..871ee43a82b8 100644
--- a/src/ui/menu-ui-handler.ts
+++ b/src/ui/menu-ui-handler.ts
@@ -15,6 +15,7 @@ import BgmBar from "#app/ui/bgm-bar";
enum MenuOptions {
GAME_SETTINGS,
ACHIEVEMENTS,
+ RUN_HISTORY,
STATS,
VOUCHERS,
EGG_LIST,
@@ -47,7 +48,7 @@ export default class MenuUiHandler extends MessageUiHandler {
protected communityConfig: OptionSelectConfig;
public bgmBar: BgmBar;
-
+ //private runHistoryCheck: boolean;
constructor(scene: BattleScene, mode?: Mode) {
super(scene, mode);
@@ -55,6 +56,8 @@ export default class MenuUiHandler extends MessageUiHandler {
this.ignoredMenuOptions = !bypassLogin
? [ ]
: [ MenuOptions.LOG_OUT ];
+ //this.ignoredMenuOptions.push(MenuOptions.RUN_HISTORY);
+ //this.runHistoryCheck = false;
this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => parseInt(MenuOptions[m]) as MenuOptions).filter(m => !this.ignoredMenuOptions.includes(m));
}
@@ -87,6 +90,7 @@ export default class MenuUiHandler extends MessageUiHandler {
this.optionSelectText = addTextObject(this.scene, 0, 0, this.menuOptions.map(o => `${i18next.t(`menuUiHandler:${MenuOptions[o]}`)}`).join("\n"), TextStyle.WINDOW, { maxLines: this.menuOptions.length });
this.optionSelectText.setLineSpacing(12);
+ this.optionSelectText.setName("MenuOptions");
this.menuBg = addWindow(this.scene, (this.scene.game.canvas.width / 6) - (this.optionSelectText.displayWidth + 25), 0, this.optionSelectText.displayWidth + 23, (this.scene.game.canvas.height / 6) - 2);
this.menuBg.setOrigin(0, 0);
@@ -264,9 +268,25 @@ export default class MenuUiHandler extends MessageUiHandler {
}
show(args: any[]): boolean {
-
super.show(args);
+ //This is here because the MenuUiConstructor is created before the user is assigned an username. Without an username, the player cannot access run history and check if it is present or not. Therefore, it is added here.
+ //I added a class variable runHistoryCheck so that the game does not need to poll getRunHistoryData every time the menu is open. show() needs to be async btw!
+ /*
+ if (await this.scene.gameData.getRunHistoryData(this.scene) && !this.runHistoryCheck) {
+ this.ignoredMenuOptions.pop();
+ this.menuOptions = Utils.getEnumKeys(MenuOptions).map(m => parseInt(MenuOptions[m]) as MenuOptions).filter(m => !this.ignoredMenuOptions.includes(m));
+ this.optionSelectText.destroy();
+ this.optionSelectText = addTextObject(this.scene, 0, 0, this.menuOptions.map(o => `${i18next.t(`menuUiHandler:${MenuOptions[o]}`)}`).join("\n"), TextStyle.WINDOW, { maxLines: this.menuOptions.length });
+ this.optionSelectText.setLineSpacing(12);
+ this.optionSelectText.setPositionRelative(this.menuBg, 14, 6);
+ this.menuContainer.remove(this.menuContainer.getByName("MenuOptions"));
+ this.optionSelectText.setName("MenuOptions");
+ this.menuContainer.add(this.optionSelectText);
+ this.runHistoryCheck = true;
+ }
+ */
+
this.menuContainer.setVisible(true);
this.setCursor(0);
@@ -280,7 +300,6 @@ export default class MenuUiHandler extends MessageUiHandler {
this.bgmBar.toggleBgmBar(true);
-
return true;
}
@@ -308,6 +327,10 @@ export default class MenuUiHandler extends MessageUiHandler {
ui.setOverlayMode(Mode.ACHIEVEMENTS);
success = true;
break;
+ case MenuOptions.RUN_HISTORY:
+ ui.setOverlayMode(Mode.RUN_HISTORY);
+ success = true;
+ break;
case MenuOptions.STATS:
ui.setOverlayMode(Mode.GAME_STATS);
success = true;
diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts
index a464a2793a52..3cfd103b4e2d 100644
--- a/src/ui/modifier-select-ui-handler.ts
+++ b/src/ui/modifier-select-ui-handler.ts
@@ -20,7 +20,6 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
private lockRarityButtonContainer: Phaser.GameObjects.Container;
private transferButtonContainer: Phaser.GameObjects.Container;
private checkButtonContainer: Phaser.GameObjects.Container;
- private continueButtonContainer: Phaser.GameObjects.Container;
private rerollCostText: Phaser.GameObjects.Text;
private lockRarityButtonText: Phaser.GameObjects.Text;
private moveInfoOverlay : MoveInfoOverlay;
@@ -101,10 +100,6 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.lockRarityButtonText.setOrigin(0, 0);
this.lockRarityButtonContainer.add(this.lockRarityButtonText);
- this.continueButtonContainer = this.scene.add.container((this.scene.game.canvas.width / 12), -(this.scene.game.canvas.height / 12));
- this.continueButtonContainer.setVisible(false);
- ui.add(this.continueButtonContainer);
-
// prepare move overlay
const overlayScale = 1;
this.moveInfoOverlay = new MoveInfoOverlay(this.scene, {
@@ -131,7 +126,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
return false;
}
- if (args.length !== 4 || !(args[1] instanceof Array) || !(args[2] instanceof Function)) {
+ if (args.length !== 4 || !(args[1] instanceof Array) || !args[1].length || !(args[2] instanceof Function)) {
return false;
}
@@ -156,9 +151,6 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.lockRarityButtonContainer.setVisible(false);
this.lockRarityButtonContainer.setAlpha(0);
- this.continueButtonContainer.setVisible(false);
- this.continueButtonContainer.setAlpha(0);
-
this.rerollButtonContainer.setPositionRelative(this.lockRarityButtonContainer, 0, canLockRarities ? -12 : 0);
this.rerollCost = args[3] as integer;
@@ -180,13 +172,6 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.options.push(option);
}
- // Add continue button
- if (this.options.length === 0) {
- const continueButtonText = addTextObject(this.scene, -24, optionsYOffset - 5, "Continue", TextStyle.MESSAGE);
- continueButtonText.setName("text-continue-btn");
- this.continueButtonContainer.add(continueButtonText);
- }
-
for (let m = 0; m < shopTypeOptions.length; m++) {
const row = m < SHOP_OPTIONS_ROW_LIMIT ? 0 : 1;
const col = m < SHOP_OPTIONS_ROW_LIMIT ? m : m - SHOP_OPTIONS_ROW_LIMIT;
@@ -250,24 +235,16 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.rerollButtonContainer.setAlpha(0);
this.checkButtonContainer.setAlpha(0);
this.lockRarityButtonContainer.setAlpha(0);
- this.continueButtonContainer.setAlpha(0);
this.rerollButtonContainer.setVisible(true);
this.checkButtonContainer.setVisible(true);
- this.continueButtonContainer.setVisible(this.rerollCost === 0);
this.lockRarityButtonContainer.setVisible(canLockRarities);
this.scene.tweens.add({
- targets: [this.lockRarityButtonContainer, this.checkButtonContainer, this.continueButtonContainer],
+ targets: [ this.rerollButtonContainer, this.lockRarityButtonContainer, this.checkButtonContainer ],
alpha: 1,
duration: 250
});
- this.scene.tweens.add({
- targets: [this.rerollButtonContainer],
- alpha: this.rerollCost === 0 ? 0.5 : 1,
- duration: 250
- });
-
this.setCursor(0);
this.setRowCursor(1);
@@ -408,14 +385,6 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
// the modifier selection has been updated, always hide the overlay
this.moveInfoOverlay.clear();
if (this.rowCursor) {
- if (this.rowCursor === 1 && options.length === 0) {
- // Continue button when no shop items
- this.cursorObj.setScale(1.25);
- this.cursorObj.setPosition((this.scene.game.canvas.width / 18) + 23, (-this.scene.game.canvas.height / 12) - (this.shopOptionsRows.length > 1 ? 6 : 22));
- ui.showText("Continue to the next wave.");
- return ret;
- }
-
const sliceWidth = (this.scene.game.canvas.width / 6) / (options.length + 2);
if (this.rowCursor < 2) {
this.cursorObj.setPosition(sliceWidth * (cursor + 1) + (sliceWidth * 0.5) - 20, (-this.scene.game.canvas.height / 12) - (this.shopOptionsRows.length > 1 ? 6 : 22));
@@ -452,14 +421,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
if (rowCursor !== lastRowCursor) {
this.rowCursor = rowCursor;
let newCursor = Math.round(this.cursor / Math.max(this.getRowItems(lastRowCursor) - 1, 1) * (this.getRowItems(rowCursor) - 1));
- if (rowCursor === 1 && this.options.length === 0) {
- // Handle empty shop
- newCursor = 0;
- }
if (rowCursor === 0) {
- if (this.options.length === 0) {
- newCursor = 1;
- }
if (newCursor === 0 && !this.rerollButtonContainer.visible) {
newCursor = 1;
}
@@ -544,7 +506,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
onComplete: () => options.forEach(o => o.destroy())
});
- [this.rerollButtonContainer, this.checkButtonContainer, this.transferButtonContainer, this.lockRarityButtonContainer, this.continueButtonContainer].forEach(container => {
+ [ this.rerollButtonContainer, this.checkButtonContainer, this.transferButtonContainer, this.lockRarityButtonContainer ].forEach(container => {
if (container.visible) {
this.scene.tweens.add({
targets: container,
diff --git a/src/ui/mystery-encounter-ui-handler.ts b/src/ui/mystery-encounter-ui-handler.ts
deleted file mode 100644
index 232d916be574..000000000000
--- a/src/ui/mystery-encounter-ui-handler.ts
+++ /dev/null
@@ -1,477 +0,0 @@
-import BattleScene from "../battle-scene";
-import { addTextObject, TextStyle } from "./text";
-import { Mode } from "./ui";
-import UiHandler from "./ui-handler";
-import { Button } from "#enums/buttons";
-import { addWindow, WindowVariant } from "./ui-theme";
-import i18next from "i18next";
-import { MysteryEncounterPhase } from "../phases/mystery-encounter-phase";
-import { PartyUiMode } from "./party-ui-handler";
-import MysteryEncounterOption from "../data/mystery-encounter-option";
-import * as Utils from "../utils";
-import { getPokeballAtlasKey } from "../data/pokeball";
-import {isNullOrUndefined} from "../utils";
-
-export default class MysteryEncounterUiHandler extends UiHandler {
- private cursorContainer: Phaser.GameObjects.Container;
- private cursorObj: Phaser.GameObjects.Image;
-
- private optionsContainer: Phaser.GameObjects.Container;
-
- private tooltipWindow: Phaser.GameObjects.NineSlice;
- private tooltipContainer: Phaser.GameObjects.Container;
- private tooltipScrollTween: Phaser.Tweens.Tween;
-
- private descriptionWindow: Phaser.GameObjects.NineSlice;
- private descriptionContainer: Phaser.GameObjects.Container;
- private descriptionScrollTween: Phaser.Tweens.Tween;
- private rarityBall: Phaser.GameObjects.Sprite;
-
- private filteredEncounterOptions: MysteryEncounterOption[] = [];
- private optionsMeetsReqs: boolean[];
-
- protected viewPartyIndex: integer = 0;
-
- protected blockInput: boolean = true;
-
- constructor(scene: BattleScene) {
- super(scene, Mode.MYSTERY_ENCOUNTER);
- }
-
- setup() {
- const ui = this.getUi();
-
- this.cursorContainer = this.scene.add.container(18, -38.7);
- this.cursorContainer.setVisible(false);
- ui.add(this.cursorContainer);
- this.optionsContainer = this.scene.add.container(12, -38.7);
- this.optionsContainer.setVisible(false);
- ui.add(this.optionsContainer);
- this.descriptionContainer = this.scene.add.container(0, -152);
- this.descriptionContainer.setVisible(false);
- ui.add(this.descriptionContainer);
- this.tooltipContainer = this.scene.add.container(210, -48);
- this.tooltipContainer.setVisible(false);
- ui.add(this.tooltipContainer);
-
- this.setCursor(this.getCursor());
-
- this.descriptionWindow = addWindow(this.scene, 0, 0, 150, 105, false, false, 0, 0, WindowVariant.THIN);
- this.descriptionContainer.add(this.descriptionWindow);
-
- this.tooltipWindow = addWindow(this.scene, 0, 0, 110, 48, false, false, 0, 0, WindowVariant.THIN);
- this.tooltipContainer.add(this.tooltipWindow);
-
- this.rarityBall = this.scene.add.sprite(141, 9, "pb");
- this.rarityBall.setScale(0.75);
- this.descriptionContainer.add(this.rarityBall);
- }
-
- show(args: any[]): boolean {
- super.show(args);
-
- this.cursorContainer.setVisible(true);
- this.descriptionContainer.setVisible(true);
- this.optionsContainer.setVisible(true);
- this.displayEncounterOptions(!(args[0] as boolean || false));
- const cursor = this.getCursor();
- if (cursor === (this?.optionsContainer?.length || 0) - 1) {
- // Always resets cursor on view party button if it was last there
- this.setCursor(cursor);
- } else {
- this.setCursor(0);
- }
- if (this.blockInput) {
- setTimeout(() => {
- this.unblockInput();
- }, 1500);
- }
- this.displayOptionTooltip();
-
- return true;
- }
-
- processInput(button: Button): boolean {
- const ui = this.getUi();
-
- let success = false;
-
- const cursor = this.getCursor();
-
- if (button === Button.CANCEL || button === Button.ACTION) {
- if (button === Button.ACTION) {
- if (cursor === this.viewPartyIndex) {
- // Handle view party
- success = true;
- this.clear();
- this.scene.ui.setMode(Mode.PARTY, PartyUiMode.CHECK, -1, () => {
- this.scene.ui.setMode(Mode.MYSTERY_ENCOUNTER, true);
- setTimeout(() => {
- this.setCursor(this.viewPartyIndex);
- this.unblockInput();
- }, 300);
- });
- } else if (this.blockInput || !this.optionsMeetsReqs[cursor]) {
- success = false;
- } else {
- const selected = this.filteredEncounterOptions[cursor];
- if ((this.scene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) {
- this.clear();
- success = true;
- } else {
- ui.playError();
- }
- }
- } else {
- // TODO: If we need to handle cancel option? Maybe default logic to leave/run from encounter idk
- }
- } else {
- switch (this.optionsContainer.length) {
- case 3:
- success = this.handleTwoOptionMoveInput(button);
- break;
- case 4:
- success = this.handleThreeOptionMoveInput(button);
- break;
- case 5:
- success = this.handleFourOptionMoveInput(button);
- break;
- }
-
- this.displayOptionTooltip();
- }
-
- if (success) {
- ui.playSelect();
- }
-
- return success;
- }
-
- handleTwoOptionMoveInput(button: Button): boolean {
- let success = false;
- const cursor = this.getCursor();
- switch (button) {
- case Button.UP:
- if (cursor < this.viewPartyIndex) {
- success = this.setCursor(this.viewPartyIndex);
- }
- break;
- case Button.DOWN:
- if (cursor === this.viewPartyIndex) {
- success = this.setCursor(1);
- }
- break;
- case Button.LEFT:
- if (cursor > 0) {
- success = this.setCursor(cursor - 1);
- }
- break;
- case Button.RIGHT:
- if (cursor < this.viewPartyIndex) {
- success = this.setCursor(cursor + 1);
- }
- break;
- }
-
- return success;
- }
-
- handleThreeOptionMoveInput(button: Button): boolean {
- let success = false;
- const cursor = this.getCursor();
- switch (button) {
- case Button.UP:
- if (cursor === 2) {
- success = this.setCursor(cursor - 2);
- } else {
- success = this.setCursor(this.viewPartyIndex);
- }
- break;
- case Button.DOWN:
- if (cursor === this.viewPartyIndex) {
- success = this.setCursor(1);
- } else {
- success = this.setCursor(2);
- }
- break;
- case Button.LEFT:
- if (cursor === this.viewPartyIndex) {
- success = this.setCursor(1);
- } else if (cursor === 1) {
- success = this.setCursor(cursor - 1);
- }
- break;
- case Button.RIGHT:
- if (cursor === 1) {
- success = this.setCursor(this.viewPartyIndex);
- } else if (cursor < 1) {
- success = this.setCursor(cursor + 1);
- }
- break;
- }
-
- return success;
- }
-
- handleFourOptionMoveInput(button: Button): boolean {
- let success = false;
- const cursor = this.getCursor();
- switch (button) {
- case Button.UP:
- if (cursor >= 2 && cursor !== this.viewPartyIndex) {
- success = this.setCursor(cursor - 2);
- } else {
- success = this.setCursor(this.viewPartyIndex);
- }
- break;
- case Button.DOWN:
- if (cursor <= 1) {
- success = this.setCursor(cursor + 2);
- } else if (cursor === this.viewPartyIndex) {
- success = this.setCursor(1);
- }
- break;
- case Button.LEFT:
- if (cursor === this.viewPartyIndex) {
- success = this.setCursor(1);
- } else if (cursor % 2 === 1) {
- success = this.setCursor(cursor - 1);
- }
- break;
- case Button.RIGHT:
- if (cursor === 1) {
- success = this.setCursor(this.viewPartyIndex);
- } else if (cursor % 2 === 0 && cursor !== this.viewPartyIndex) {
- success = this.setCursor(cursor + 1);
- }
- break;
- }
-
- return success;
- }
-
- unblockInput() {
- if (this.blockInput) {
- this.blockInput = false;
- for (let i = 0; i < this.optionsContainer.length - 1; i++) {
- if (!this.optionsMeetsReqs[i]) {
- continue;
- }
- (this.optionsContainer.getAt(i) as Phaser.GameObjects.Text).setAlpha(1);
- }
- }
- }
-
- getCursor(): integer {
- return this.cursor ? this.cursor : 0;
- }
-
- setCursor(cursor: integer): boolean {
- const prevCursor = this.getCursor();
- const changed = prevCursor !== cursor;
- if (changed) {
- this.cursor = cursor;
- }
-
- this.viewPartyIndex = this.optionsContainer.length - 1;
-
- if (!this.cursorObj) {
- this.cursorObj = this.scene.add.image(0, 0, "cursor");
- this.cursorContainer.add(this.cursorObj);
- }
-
- if (cursor === this.viewPartyIndex) {
- this.cursorObj.setPosition(246, -17);
- } else if (this.optionsContainer.length === 3) { // 2 Options
- this.cursorObj.setPosition(-10.5 + (cursor % 2 === 1 ? 100 : 0), 15);
- } else if (this.optionsContainer.length === 4) { // 3 Options
- this.cursorObj.setPosition(-10.5 + (cursor % 2 === 1 ? 100 : 0), 7 + (cursor > 1 ? 16 : 0));
- } else if (this.optionsContainer.length === 5) { // 4 Options
- this.cursorObj.setPosition(-10.5 + (cursor % 2 === 1 ? 100 : 0), 7 + (cursor > 1 ? 16 : 0));
- }
-
- return changed;
- }
-
- displayEncounterOptions(slideInDescription: boolean = true): void {
- this.getUi().clearText();
- const mysteryEncounter = this.scene.currentBattle.mysteryEncounter;
- this.filteredEncounterOptions = mysteryEncounter.options;
- this.optionsMeetsReqs = [];
-
- const titleText: string = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.title);
- const descriptionText: string = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.description);
- const queryText: string = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.query);
-
- // Clear options container (except cursor)
- this.optionsContainer.removeAll();
-
- // Options Window
- for (let i = 0; i < this.filteredEncounterOptions.length; i++) {
- let optionText;
- switch (this.filteredEncounterOptions.length) {
- case 2:
- optionText = addTextObject(this.scene, i % 2 === 0 ? 0 : 100, 8, "-", TextStyle.WINDOW, { wordWrap: { width: 558 }, fontSize: "80px", lineSpacing: -8 });
- break;
- case 3:
- optionText = addTextObject(this.scene, i % 2 === 0 ? 0 : 100, i < 2 ? 0 : 16, "-", TextStyle.WINDOW, { wordWrap: { width: 558 }, fontSize: "80px", lineSpacing: -8 });
- break;
- case 4:
- optionText = addTextObject(this.scene, i % 2 === 0 ? 0 : 100, i < 2 ? 0 : 16, "-", TextStyle.WINDOW, { wordWrap: { width: 558 }, fontSize: "80px", lineSpacing: -8 });
- break;
- }
- const text = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.options[i].buttonLabel);
- if (text) {
- optionText.setText(text);
- }
-
- this.optionsMeetsReqs.push(this.filteredEncounterOptions[i].meetsRequirements(this.scene));
-
- if (!this.optionsMeetsReqs[i]) {
- optionText.setAlpha(0.5);
- }
- if (this.blockInput) {
- optionText.setAlpha(0.5);
- }
- this.optionsContainer.add(optionText);
- }
-
- // View Party Button
- const viewPartyText = addTextObject(this.scene, 256, -24, "View Party", TextStyle.PARTY);
- this.optionsContainer.add(viewPartyText);
-
- // Description Window
- const titleTextObject = addTextObject(this.scene, 0, 0, titleText, TextStyle.TOOLTIP_TITLE, { wordWrap: { width: 750 }, align: "center", lineSpacing: -8 });
- this.descriptionContainer.add(titleTextObject);
- titleTextObject.setPosition(72 - titleTextObject.displayWidth / 2, 5.5);
-
- // Rarity of encounter
- const ballType = getPokeballAtlasKey(mysteryEncounter.encounterTier as number);
- this.rarityBall.setTexture("pb", ballType);
-
- const descriptionTextObject = addTextObject(this.scene, 6, 25, descriptionText, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } });
-
- // Sets up the mask that hides the description text to give an illusion of scrolling
- const descriptionTextMaskRect = this.scene.make.graphics({});
- descriptionTextMaskRect.setScale(6);
- descriptionTextMaskRect.fillStyle(0xFFFFFF);
- descriptionTextMaskRect.beginPath();
- descriptionTextMaskRect.fillRect(6, 54, 206, 60);
-
- const abilityDescriptionTextMask = descriptionTextMaskRect.createGeometryMask();
-
- descriptionTextObject.setMask(abilityDescriptionTextMask);
-
- const descriptionLineCount = Math.floor(descriptionTextObject.displayHeight / 10);
-
- if (this.descriptionScrollTween) {
- this.descriptionScrollTween.remove();
- this.descriptionScrollTween = null;
- }
-
- // Animates the description text moving upwards
- if (descriptionLineCount > 6) {
- this.descriptionScrollTween = this.scene.tweens.add({
- targets: descriptionTextObject,
- delay: Utils.fixedInt(2000),
- loop: -1,
- hold: Utils.fixedInt(2000),
- duration: Utils.fixedInt((descriptionLineCount - 6) * 2000),
- y: `-=${10 * (descriptionLineCount - 6)}`
- });
- }
-
- this.descriptionContainer.add(descriptionTextObject);
-
- const queryTextObject = addTextObject(this.scene, 65 - (queryText.length), 90, queryText, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 830 } });
- this.descriptionContainer.add(queryTextObject);
-
- // Slide in description container
- if (slideInDescription) {
- this.descriptionContainer.x -= 150;
- this.scene.tweens.add({
- targets: this.descriptionContainer,
- x: "+=150",
- ease: "Sine.easeInOut",
- duration: 1000
- });
- }
- }
-
- displayOptionTooltip() {
- const cursor = this.getCursor();
- // Clear tooltip box
- if (this.tooltipContainer.length > 1) {
- this.tooltipContainer.removeBetween(1, this.tooltipContainer.length, true);
- }
- this.tooltipContainer.setVisible(true);
-
- if (isNullOrUndefined(cursor) || cursor > this.optionsContainer.length - 2) {
- // Ignore hovers on view party button
- return;
- }
-
- const mysteryEncounter = this.scene.currentBattle.mysteryEncounter;
- let text;
- if (!this.optionsMeetsReqs[cursor] && mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor].disabledTooltip) {
- text = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor].disabledTooltip);
- } else {
- text = i18next.t(mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor].buttonTooltip);
- }
-
-
- if (text) {
- const tooltipTextObject = addTextObject(this.scene, 6, 7, text, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 600 }, fontSize: "72px" });
- this.tooltipContainer.add(tooltipTextObject);
-
- // Sets up the mask that hides the description text to give an illusion of scrolling
- const tooltipTextMaskRect = this.scene.make.graphics({});
- tooltipTextMaskRect.setScale(6);
- tooltipTextMaskRect.fillStyle(0xFFFFFF);
- tooltipTextMaskRect.beginPath();
- tooltipTextMaskRect.fillRect(this.tooltipContainer.x, this.tooltipContainer.y + 188.5, 150, 32);
-
- const textMask = tooltipTextMaskRect.createGeometryMask();
- tooltipTextObject.setMask(textMask);
-
- const tooltipLineCount = Math.floor(tooltipTextObject.displayHeight / 11.2);
-
- if (this.tooltipScrollTween) {
- this.tooltipScrollTween.remove();
- this.tooltipScrollTween = null;
- }
-
- // Animates the tooltip text moving upwards
- if (tooltipLineCount > 3) {
- this.tooltipScrollTween = this.scene.tweens.add({
- targets: tooltipTextObject,
- delay: Utils.fixedInt(1200),
- loop: -1,
- hold: Utils.fixedInt(1200),
- duration: Utils.fixedInt((tooltipLineCount - 3) * 1200),
- y: `-=${11.2 * (tooltipLineCount - 3)}`
- });
- }
- }
- }
-
- clear(): void {
- super.clear();
- this.optionsContainer.setVisible(false);
- this.optionsContainer.removeAll(true);
- this.descriptionContainer.setVisible(false);
- this.tooltipContainer.setVisible(false);
- // Keeps container background and pokeball
- this.descriptionContainer.removeBetween(2, this.descriptionContainer.length, true);
- this.getUi().getMessageHandler().clearText();
- this.eraseCursor();
- }
-
- eraseCursor(): void {
- if (this.cursorObj) {
- this.cursorObj.destroy();
- }
- this.cursorObj = null;
- }
-}
diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts
index 9c2c57f12d5b..e820c8cb0d2d 100644
--- a/src/ui/party-ui-handler.ts
+++ b/src/ui/party-ui-handler.ts
@@ -1,4 +1,4 @@
-import { CommandPhase } from "../phases";
+import { CommandPhase, SelectModifierPhase } from "../phases";
import BattleScene from "../battle-scene";
import { PlayerPokemon, PokemonMove } from "../field/pokemon";
import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text";
@@ -21,7 +21,6 @@ import MoveInfoOverlay from "./move-info-overlay";
import i18next from "i18next";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Moves } from "#enums/moves";
-import {SelectModifierPhase} from "#app/phases/select-modifier-phase";
const defaultMessage = i18next.t("partyUiHandler:choosePokemon");
@@ -37,8 +36,7 @@ export enum PartyUiMode {
MODIFIER_TRANSFER,
SPLICE,
RELEASE,
- CHECK,
- SELECT
+ CHECK
}
export enum PartyOption {
@@ -54,7 +52,6 @@ export enum PartyOption {
SPLICE,
UNSPLICE,
RELEASE,
- SELECT,
SCROLL_UP = 1000,
SCROLL_DOWN = 1001,
FORM_CHANGE_ITEM = 2000,
@@ -156,7 +153,7 @@ export default class PartyUiHandler extends MessageUiHandler {
public static NoEffectMessage = i18next.t("partyUiHandler:anyEffect");
- private localizedOptions = [PartyOption.SEND_OUT, PartyOption.SUMMARY, PartyOption.CANCEL, PartyOption.APPLY, PartyOption.RELEASE, PartyOption.TEACH, PartyOption.SPLICE, PartyOption.UNSPLICE, PartyOption.REVIVE, PartyOption.TRANSFER, PartyOption.UNPAUSE_EVOLUTION, PartyOption.PASS_BATON, PartyOption.SELECT];
+ private localizedOptions = [PartyOption.SEND_OUT, PartyOption.SUMMARY, PartyOption.CANCEL, PartyOption.APPLY, PartyOption.RELEASE, PartyOption.TEACH, PartyOption.SPLICE, PartyOption.UNSPLICE, PartyOption.REVIVE, PartyOption.TRANSFER, PartyOption.UNPAUSE_EVOLUTION, PartyOption.PASS_BATON];
constructor(scene: BattleScene) {
super(scene, Mode.PARTY);
@@ -289,36 +286,6 @@ export default class PartyUiHandler extends MessageUiHandler {
const pokemon = this.scene.getParty()[this.cursor];
if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode && option !== PartyOption.CANCEL) {
this.startTransfer();
-
- let ableToTransfer: string;
- for (let p = 0; p < this.scene.getParty().length; p++) { // this fore look goes through each of the party pokemon
- const newPokemon = this.scene.getParty()[p];
- // this next line gets all of the transferable items from pokemon [p]; it does this by getting all the held modifiers that are transferable and checking to see if they belong to pokemon [p]
- const getTransferrableItemsFromPokemon = (newPokemon: PlayerPokemon) =>
- this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === newPokemon.id) as PokemonHeldItemModifier[];
- // this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon [p]; this returns undefined if the new pokemon doesn't have the item at all, otherwise it returns the pokemonHeldItemModifier for that item
- const matchingModifier = newPokemon.scene.findModifier(m => m instanceof PokemonHeldItemModifier && m.pokemonId === newPokemon.id && m.matchType(getTransferrableItemsFromPokemon(pokemon)[this.transferOptionCursor])) as PokemonHeldItemModifier;
- const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us
- if (p !== this.transferCursor) { // this skips adding the able/not able labels on the pokemon doing the transfer
- if (matchingModifier) { // if matchingModifier exists then the item exists on the new pokemon
- if (matchingModifier.getMaxStackCount(this.scene) === matchingModifier.stackCount) { // checks to see if the stack of items is at max stack; if so, set the description label to "Not able"
- ableToTransfer = "Not able";
- } else { // if the pokemon isn't at max stack, make the label "Able"
- ableToTransfer = "Able";
- }
- } else { // if matchingModifier doesn't exist, that means the pokemon doesn't have any of the item, and we need to show "Able"
- ableToTransfer = "Able";
- }
- } else { // this else relates to the transfer pokemon. We set the text to be blank so there's no "Able"/"Not able" text
- ableToTransfer = "";
- }
- partySlot.slotHpBar.setVisible(false);
- partySlot.slotHpOverlay.setVisible(false);
- partySlot.slotHpText.setVisible(false);
- partySlot.slotDescriptionLabel.setText(ableToTransfer);
- partySlot.slotDescriptionLabel.setVisible(true);
- }
-
this.clearOptions();
ui.playSelect();
return true;
@@ -451,10 +418,6 @@ export default class PartyUiHandler extends MessageUiHandler {
return true;
} else if (option === PartyOption.CANCEL) {
return this.processInput(Button.CANCEL);
- } else if (option === PartyOption.SELECT) {
- ui.playSelect();
- // ui.setModeWithoutClear(Mode.SUMMARY, pokemon).then(() => this.clearOptions());
- return true;
}
} else if (button === Button.CANCEL) {
this.clearOptions();
@@ -796,9 +759,6 @@ export default class PartyUiHandler extends MessageUiHandler {
}
}
break;
- case PartyUiMode.SELECT:
- this.options.push(PartyOption.SELECT);
- break;
}
this.options.push(PartyOption.SUMMARY);
@@ -965,12 +925,6 @@ export default class PartyUiHandler extends MessageUiHandler {
this.transferMode = false;
this.transferAll = false;
this.partySlots[this.transferCursor].setTransfer(false);
- for (let i = 0; i < this.partySlots.length; i++) {
- this.partySlots[i].slotDescriptionLabel.setVisible(false);
- this.partySlots[i].slotHpBar.setVisible(true);
- this.partySlots[i].slotHpOverlay.setVisible(true);
- this.partySlots[i].slotHpText.setVisible(true);
- }
}
doRelease(slotIndex: integer): void {
@@ -1065,12 +1019,6 @@ class PartySlot extends Phaser.GameObjects.Container {
private slotBg: Phaser.GameObjects.Image;
private slotPb: Phaser.GameObjects.Sprite;
- public slotName: Phaser.GameObjects.Text;
- public slotHpBar: Phaser.GameObjects.Image;
- public slotHpOverlay: Phaser.GameObjects.Sprite;
- public slotHpText: Phaser.GameObjects.Text;
- public slotDescriptionLabel: Phaser.GameObjects.Text; // this is used to show text instead of the HP bar i.e. for showing "Able"/"Not Able" for TMs when you try to learn them
-
private pokemonIcon: Phaser.GameObjects.Container;
private iconAnimHandler: PokemonIconAnimHandler;
@@ -1087,10 +1035,6 @@ class PartySlot extends Phaser.GameObjects.Container {
this.setup(partyUiMode, tmMoveId);
}
- getPokemon(): PlayerPokemon {
- return this.pokemon;
- }
-
setup(partyUiMode: PartyUiMode, tmMoveId: Moves) {
const battlerCount = (this.scene as BattleScene).currentBattle.getBattlerCount();
@@ -1129,19 +1073,19 @@ class PartySlot extends Phaser.GameObjects.Container {
nameSizeTest.destroy();
- this.slotName = addTextObject(this.scene, 0, 0, displayName, TextStyle.PARTY);
- this.slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10);
- this.slotName.setOrigin(0, 0);
+ const slotName = addTextObject(this.scene, 0, 0, displayName, TextStyle.PARTY);
+ slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10);
+ slotName.setOrigin(0, 0);
const slotLevelLabel = this.scene.add.image(0, 0, "party_slot_overlay_lv");
- slotLevelLabel.setPositionRelative(this.slotName, 8, 12);
+ slotLevelLabel.setPositionRelative(slotName, 8, 12);
slotLevelLabel.setOrigin(0, 0);
const slotLevelText = addTextObject(this.scene, 0, 0, this.pokemon.level.toString(), this.pokemon.level < (this.scene as BattleScene).getMaxExpLevel() ? TextStyle.PARTY : TextStyle.PARTY_RED);
slotLevelText.setPositionRelative(slotLevelLabel, 9, 0);
slotLevelText.setOrigin(0, 0.25);
- slotInfoContainer.add([this.slotName, slotLevelLabel, slotLevelText ]);
+ slotInfoContainer.add([ slotName, slotLevelLabel, slotLevelText ]);
const genderSymbol = getGenderSymbol(this.pokemon.getGender(true));
@@ -1152,7 +1096,7 @@ class PartySlot extends Phaser.GameObjects.Container {
if (this.slotIndex >= battlerCount) {
slotGenderText.setPositionRelative(slotLevelLabel, 36, 0);
} else {
- slotGenderText.setPositionRelative(this.slotName, 76 - (this.pokemon.fusionSpecies ? 8 : 0), 3);
+ slotGenderText.setPositionRelative(slotName, 76 - (this.pokemon.fusionSpecies ? 8 : 0), 3);
}
slotGenderText.setOrigin(0, 0.25);
@@ -1166,7 +1110,7 @@ class PartySlot extends Phaser.GameObjects.Container {
if (this.slotIndex >= battlerCount) {
splicedIcon.setPositionRelative(slotLevelLabel, 36 + (genderSymbol ? 8 : 0), 0.5);
} else {
- splicedIcon.setPositionRelative(this.slotName, 76, 3.5);
+ splicedIcon.setPositionRelative(slotName, 76, 3.5);
}
slotInfoContainer.add(splicedIcon);
@@ -1186,7 +1130,7 @@ class PartySlot extends Phaser.GameObjects.Container {
const shinyStar = this.scene.add.image(0, 0, `shiny_star_small${doubleShiny ? "_1" : ""}`);
shinyStar.setOrigin(0, 0);
- shinyStar.setPositionRelative(this.slotName, -9, 3);
+ shinyStar.setPositionRelative(slotName, -9, 3);
shinyStar.setTint(getVariantTint(!doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant));
slotInfoContainer.add(shinyStar);
@@ -1201,40 +1145,24 @@ class PartySlot extends Phaser.GameObjects.Container {
}
}
- this.slotHpBar = this.scene.add.image(0, 0, "party_slot_hp_bar");
- this.slotHpBar.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 72 : 8, this.slotIndex >= battlerCount ? 6 : 31);
- this.slotHpBar.setOrigin(0, 0);
- this.slotHpBar.setVisible(false);
-
- const hpRatio = this.pokemon.getHpRatio();
-
- this.slotHpOverlay = this.scene.add.sprite(0, 0, "party_slot_hp_overlay", hpRatio > 0.5 ? "high" : hpRatio > 0.25 ? "medium" : "low");
- this.slotHpOverlay.setPositionRelative(this.slotHpBar, 16, 2);
- this.slotHpOverlay.setOrigin(0, 0);
- this.slotHpOverlay.setScale(hpRatio, 1);
- this.slotHpOverlay.setVisible(false);
+ if (partyUiMode !== PartyUiMode.TM_MODIFIER) {
+ const slotHpBar = this.scene.add.image(0, 0, "party_slot_hp_bar");
+ slotHpBar.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 72 : 8, this.slotIndex >= battlerCount ? 6 : 31);
+ slotHpBar.setOrigin(0, 0);
- this.slotHpText = addTextObject(this.scene, 0, 0, `${this.pokemon.hp}/${this.pokemon.getMaxHp()}`, TextStyle.PARTY);
- this.slotHpText.setPositionRelative(this.slotHpBar, this.slotHpBar.width - 3, this.slotHpBar.height - 2);
- this.slotHpText.setOrigin(1, 0);
- this.slotHpText.setVisible(false);
+ const hpRatio = this.pokemon.getHpRatio();
- this.slotDescriptionLabel = addTextObject(this.scene, 0, 0, "", TextStyle.MESSAGE);
- this.slotDescriptionLabel.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 94 : 32, this.slotIndex >= battlerCount ? 16 : 46);
- this.slotDescriptionLabel.setOrigin(0, 1);
- this.slotDescriptionLabel.setVisible(false);
+ const slotHpOverlay = this.scene.add.sprite(0, 0, "party_slot_hp_overlay", hpRatio > 0.5 ? "high" : hpRatio > 0.25 ? "medium" : "low");
+ slotHpOverlay.setPositionRelative(slotHpBar, 16, 2);
+ slotHpOverlay.setOrigin(0, 0);
+ slotHpOverlay.setScale(hpRatio, 1);
- slotInfoContainer.add([this.slotHpBar, this.slotHpOverlay, this.slotHpText, this.slotDescriptionLabel]);
+ const slotHpText = addTextObject(this.scene, 0, 0, `${this.pokemon.hp}/${this.pokemon.getMaxHp()}`, TextStyle.PARTY);
+ slotHpText.setPositionRelative(slotHpBar, slotHpBar.width - 3, slotHpBar.height - 2);
+ slotHpText.setOrigin(1, 0);
- if (partyUiMode !== PartyUiMode.TM_MODIFIER) {
- this.slotDescriptionLabel.setVisible(false);
- this.slotHpBar.setVisible(true);
- this.slotHpOverlay.setVisible(true);
- this.slotHpText.setVisible(true);
+ slotInfoContainer.add([ slotHpBar, slotHpOverlay, slotHpText ]);
} else {
- this.slotHpBar.setVisible(false);
- this.slotHpOverlay.setVisible(false);
- this.slotHpText.setVisible(false);
let slotTmText: string;
switch (true) {
case (this.pokemon.compatibleTms.indexOf(tmMoveId) === -1):
@@ -1248,9 +1176,11 @@ class PartySlot extends Phaser.GameObjects.Container {
break;
}
- this.slotDescriptionLabel.setText(slotTmText);
- this.slotDescriptionLabel.setVisible(true);
+ const slotTmLabel = addTextObject(this.scene, 0, 0, slotTmText, TextStyle.MESSAGE);
+ slotTmLabel.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 94 : 32, this.slotIndex >= battlerCount ? 16 : 46);
+ slotTmLabel.setOrigin(0, 1);
+ slotInfoContainer.add(slotTmLabel);
}
}
diff --git a/src/ui/run-history-ui-handler.ts b/src/ui/run-history-ui-handler.ts
new file mode 100644
index 000000000000..845a468091ee
--- /dev/null
+++ b/src/ui/run-history-ui-handler.ts
@@ -0,0 +1,368 @@
+import BattleScene from "../battle-scene";
+import { GameModes } from "../game-mode";
+import { TextStyle, addTextObject } from "./text";
+import { Mode } from "./ui";
+import { addWindow } from "./ui-theme";
+import * as Utils from "../utils";
+import PokemonData from "../system/pokemon-data";
+import MessageUiHandler from "./message-ui-handler";
+import i18next from "i18next";
+import {Button} from "../enums/buttons";
+import { BattleType } from "../battle";
+import { TrainerVariant } from "../field/trainer";
+import { Challenges } from "#enums/challenges";
+import { Type } from "../data/type";
+import { RunHistoryData } from "../system/game-data";
+
+
+export const runCount = 25;
+
+export type RunSelectCallback = (cursor: integer) => void;
+
+export default class RunHistoryUiHandler extends MessageUiHandler {
+
+ private runSelectContainer: Phaser.GameObjects.Container;
+ private runsContainer: Phaser.GameObjects.Container;
+ private runSelectMessageBox: Phaser.GameObjects.NineSlice;
+ private runSelectMessageBoxContainer: Phaser.GameObjects.Container;
+ private runs: RunEntry[];
+
+ private runSelectCallback: RunSelectCallback;
+
+ private scrollCursor: integer = 0;
+
+ private cursorObj: Phaser.GameObjects.NineSlice;
+
+ private runContainerInitialY: number;
+
+ constructor(scene: BattleScene) {
+ super(scene, Mode.RUN_HISTORY);
+ }
+
+ setup() {
+ const ui = this.getUi();
+
+ this.runSelectContainer = this.scene.add.container(0, 0);
+ this.runSelectContainer.setVisible(false);
+ ui.add(this.runSelectContainer);
+
+ const loadSessionBg = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, -this.scene.game.canvas.height / 6, 0x006860);
+ loadSessionBg.setOrigin(0, 0);
+ this.runSelectContainer.add(loadSessionBg);
+
+ this.runContainerInitialY = -this.scene.game.canvas.height / 6 + 8;
+
+ this.runsContainer = this.scene.add.container(8, this.runContainerInitialY);
+ this.runSelectContainer.add(this.runsContainer);
+
+ this.runSelectMessageBoxContainer = this.scene.add.container(0, 0);
+ this.runSelectMessageBoxContainer.setVisible(false);
+ this.runSelectContainer.add(this.runSelectMessageBoxContainer);
+
+ this.runSelectMessageBox = addWindow(this.scene, 1, -1, 318, 28);
+ this.runSelectMessageBox.setOrigin(0, 1);
+ this.runSelectMessageBoxContainer.add(this.runSelectMessageBox);
+
+ this.message = addTextObject(this.scene, 8, 8, "", TextStyle.WINDOW, { maxLines: 2 });
+ this.message.setOrigin(0, 0);
+ this.runSelectMessageBoxContainer.add(this.message);
+
+ this.runs = [];
+ }
+
+ show(args: any[]): boolean {
+ super.show(args);
+
+ this.getUi().bringToTop(this.runSelectContainer);
+ this.runSelectContainer.setVisible(true);
+ this.populateruns(this.scene);
+
+ this.setScrollCursor(0);
+ this.setCursor(0);
+
+ return true;
+ }
+
+ processInput(button: Button): boolean {
+ const ui = this.getUi();
+
+ let success = false;
+ const error = false;
+
+ if (button === Button.ACTION || button === Button.CANCEL) {
+ if (button === Button.ACTION) {
+ const cursor = this.cursor + this.scrollCursor;
+ if (this.runs[cursor].hasData) {
+ this.scene.ui.setOverlayMode(Mode.RUN_INFO, this.runs[cursor].entryData, true);
+ }
+ success = true;
+ return success;
+ } else {
+ this.runSelectCallback = null;
+ success = true;
+ this.scene.ui.revertMode();
+ }
+ } else {
+ switch (button) {
+ case Button.UP:
+ if (this.cursor) {
+ success = this.setCursor(this.cursor - 1);
+ } else if (this.scrollCursor) {
+ success = this.setScrollCursor(this.scrollCursor - 1);
+ }
+ break;
+ case Button.DOWN:
+ if (this.cursor < 2) {
+ success = this.setCursor(this.cursor + 1);
+ } else if (this.scrollCursor < runCount - 3) {
+ success = this.setScrollCursor(this.scrollCursor + 1);
+ }
+ break;
+ }
+ }
+
+ if (success) {
+ ui.playSelect();
+ } else if (error) {
+ ui.playError();
+ }
+ return success || error;
+ }
+
+
+ async populateruns(scene: BattleScene) {
+ const response = await this.scene.gameData.getRunHistoryData(this.scene);
+ const timestamps = Object.keys(response);
+ const timestampsNo = timestamps.map(Number);
+ if (timestamps.length > 1) {
+ timestampsNo.sort((a, b) => a - b);
+ }
+ const entryCount = timestamps.length;
+ for (let s = 0; s < entryCount; s++) {
+ const entry = new RunEntry(this.scene, response, timestampsNo[s].toString(), s);
+ this.scene.add.existing(entry);
+ this.runsContainer.add(entry);
+ this.runs.push(entry);
+ }
+ }
+
+ showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) {
+ super.showText(text, delay, callback, callbackDelay, prompt, promptDelay);
+
+ if (text?.indexOf("\n") === -1) {
+ this.runSelectMessageBox.setSize(318, 28);
+ this.message.setY(-22);
+ } else {
+ this.runSelectMessageBox.setSize(318, 42);
+ this.message.setY(-37);
+ }
+
+ this.runSelectMessageBoxContainer.setVisible(!!text?.length);
+ }
+
+ setCursor(cursor: integer): boolean {
+ const changed = super.setCursor(cursor);
+
+ if (!this.cursorObj) {
+ this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight_thick", null, 296, 44, 6, 6, 6, 6);
+ this.cursorObj.setOrigin(0, 0);
+ this.runsContainer.add(this.cursorObj);
+ }
+ this.cursorObj.setPosition(4, 4 + (cursor + this.scrollCursor) * 56);
+
+ return changed;
+ }
+
+ setScrollCursor(scrollCursor: integer): boolean {
+ const changed = scrollCursor !== this.scrollCursor;
+
+ if (changed) {
+ this.scrollCursor = scrollCursor;
+ this.setCursor(this.cursor);
+ this.scene.tweens.add({
+ targets: this.runsContainer,
+ y: this.runContainerInitialY - 56 * scrollCursor,
+ duration: Utils.fixedInt(325),
+ ease: "Sine.easeInOut"
+ });
+ }
+
+ return changed;
+ }
+
+ clear() {
+ super.clear();
+ this.runSelectContainer.setVisible(false);
+ this.eraseCursor();
+ this.runSelectCallback = null;
+ this.clearruns();
+ }
+
+ eraseCursor() {
+ if (this.cursorObj) {
+ this.cursorObj.destroy();
+ }
+ this.cursorObj = null;
+ }
+
+ clearruns() {
+ this.runs.splice(0, this.runs.length);
+ this.runsContainer.removeAll(true);
+ }
+}
+
+class RunEntry extends Phaser.GameObjects.Container {
+ public slotId: integer;
+ public hasData: boolean;
+ public entryData: RunHistoryData;
+ private loadingLabel: Phaser.GameObjects.Text;
+
+ constructor(scene: BattleScene, runHistory: any, timestamp: string, slotId: integer) {
+ super(scene, 0, slotId*56);
+
+ this.slotId = slotId;
+ this.hasData = true;
+ this.entryData = runHistory[timestamp];
+
+ this.setup(this.entryData);
+
+ }
+
+ setup(run: any) {
+
+ const victory = run.victory;
+ const data = this.scene.gameData.parseSessionData(JSON.stringify(run.entry));
+
+ const slotWindow = addWindow(this.scene, 0, 0, 304, 52);
+ this.add(slotWindow);
+
+
+ if (victory) {
+ const gameOutcomeLabel = addTextObject(this.scene, 8, 5, `${i18next.t("runHistory:victory")}`, TextStyle.WINDOW);
+ this.add(gameOutcomeLabel);
+ } else {
+ if (data.battleType === BattleType.WILD) {
+ const enemyContainer = this.scene.add.container(8, 5);
+ const gameOutcomeLabel = addTextObject(this.scene, 0, 0, `${i18next.t("runHistory:defeatedWild")}`, TextStyle.WINDOW);
+ enemyContainer.add(gameOutcomeLabel);
+ data.enemyParty.forEach((enemyData, e) => {
+ //This allows the enemyParty to be shown - doubles or sings -> 58+(e*8)
+ const enemyIconContainer = this.scene.add.container(65+(e*25),-8);
+ enemyIconContainer.setScale(0.75);
+ enemyData.boss = false;
+ const enemy = enemyData.toPokemon(this.scene);
+ const enemyIcon = this.scene.addPokemonIcon(enemy, 0, 0, 0, 0);
+ const enemyLevel = addTextObject(this.scene, 32, 20, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" });
+ enemyLevel.setShadow(0, 0, null);
+ enemyLevel.setStroke("#424242", 14);
+ enemyLevel.setOrigin(1, 0);
+ enemyIconContainer.add(enemyIcon);
+ enemyIconContainer.add(enemyLevel);
+ enemyContainer.add(enemyIconContainer);
+ enemy.destroy();
+ });
+ this.add(enemyContainer);
+ } else if (data.battleType === BattleType.TRAINER) {
+ const tObj = data.trainer.toTrainer(this.scene);
+ if (data.trainer.trainerType >= 375) {
+ const gameOutcomeLabel = addTextObject(this.scene, 8, 5, `${i18next.t("runHistory:defeatedRival")}`, TextStyle.WINDOW);
+ //otherwise it becomes Rival_5 in Ivy's case
+ this.add(gameOutcomeLabel);
+ } else if (data.trainer.variant === TrainerVariant.DOUBLE) {
+ const gameOutcomeLabel = addTextObject(this.scene, 8, 5, `${i18next.t("runHistory:defeatedTrainer")+tObj.config.nameDouble+" "+tObj.getName(0, false)}`, TextStyle.WINDOW);
+ this.add(gameOutcomeLabel);
+ } else {
+ const gameOutcomeLabel = addTextObject(this.scene, 8, 5, `${i18next.t("runHistory:defeatedTrainer")+tObj.getName(0, true)}`, TextStyle.WINDOW);
+ this.add(gameOutcomeLabel);
+ }
+ }
+ }
+
+ const gameModeLabel = addTextObject(this.scene, 8, 19, "", TextStyle.WINDOW);
+ switch (data.gameMode) {
+ case GameModes.DAILY:
+ gameModeLabel.appendText(`${i18next.t("gameMode:dailyRun")}`, false);
+ break;
+ case GameModes.SPLICED_ENDLESS:
+ gameModeLabel.appendText(`${i18next.t("gameMode:splicedEndless")}`, false);
+ break;
+ case GameModes.ENDLESS:
+ gameModeLabel.appendText(`${i18next.t("gameMode:endless")}`, false);
+ break;
+ case GameModes.CLASSIC:
+ gameModeLabel.appendText(`${i18next.t("gameMode:classic")}`, false);
+ break;
+ case GameModes.CHALLENGE:
+ gameModeLabel.appendText(`${i18next.t("gameMode:challenge")}`, false);
+ break;
+ }
+ gameModeLabel.appendText(" - ", false);
+ gameModeLabel.appendText(i18next.t("saveSlotSelectUiHandler:wave")+" "+data.waveIndex, false);
+ this.add(gameModeLabel);
+
+ const timestampLabel = addTextObject(this.scene, 8, 33, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW);
+ this.add(timestampLabel);
+
+ const pokemonIconsContainer = this.scene.add.container(125, 17);
+
+ data.party.forEach((p: PokemonData, i: integer) => {
+ const iconContainer = this.scene.add.container(26 * i, 0);
+ iconContainer.setScale(0.75);
+ const pokemon = p.toPokemon(this.scene);
+ const icon = this.scene.addPokemonIcon(pokemon, 0, 0, 0, 0);
+
+ const text = addTextObject(this.scene, 32, 20, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" });
+ text.setShadow(0, 0, null);
+ text.setStroke("#424242", 14);
+ text.setOrigin(1, 0);
+
+ iconContainer.add(icon);
+ iconContainer.add(text);
+
+ pokemonIconsContainer.add(iconContainer);
+
+ pokemon.destroy();
+ });
+
+ this.add(pokemonIconsContainer);
+
+ //Display Score - only visible for Daily Mode
+ //Display Personal Best - only visible for Endless Modes
+ switch (data.gameMode) {
+ case GameModes.ENDLESS:
+ case GameModes.SPLICED_ENDLESS:
+ if (this.scene.gameData.gameStats.highestEndlessWave === data.waveIndex) {
+ const personalBestText = addTextObject(this.scene, 255, 5, `${i18next.t("runHistory:personalBest")}`, TextStyle.WINDOW, {fontSize: "44px"});
+ personalBestText.setTint(0xffef5c, 0x47ff69, 0x6b6bff, 0xff6969);
+ this.add(personalBestText);
+ }
+ break;
+ case GameModes.CHALLENGE:
+ const allChallenges = data.challenges;
+ for (let i = 0; i < allChallenges.length; i++) {
+ const runChallenge = allChallenges[i];
+ const challengeLabel = addTextObject(this.scene, 270, 5, "", TextStyle.WINDOW, {fontSize: "40px"});
+ if (runChallenge.id === Challenges.SINGLE_GENERATION && runChallenge.value !== 0) {
+ const genValue = i18next.t(`runHistory:challengeMonoGen${runChallenge.value.toString()}` as const);
+ challengeLabel.appendText(genValue, false);
+ }
+ if (runChallenge.id === Challenges.SINGLE_TYPE && runChallenge.value !== 0) {
+ const typeValue = i18next.t(`pokemonInfo:Type.${Type[runChallenge.value-1]}` as const);
+ if (challengeLabel.text) {
+ challengeLabel.appendText(typeValue);
+ } else {
+ challengeLabel.appendText(typeValue, false);
+ }
+ }
+ this.add(challengeLabel);
+ }
+ break;
+ }
+ }
+}
+
+
+interface RunEntry {
+ scene: BattleScene;
+}
+
diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts
new file mode 100644
index 000000000000..4cd37bb818fa
--- /dev/null
+++ b/src/ui/run-info-ui-handler.ts
@@ -0,0 +1,513 @@
+import BattleScene from "../battle-scene";
+import { GameModes } from "../game-mode";
+import UiHandler from "./ui-handler";
+import { SessionSaveData } from "../system/game-data";
+import { TextStyle, addTextObject, addBBCodeTextObject } from "./text";
+import { Mode } from "./ui";
+import { addWindow } from "./ui-theme";
+import * as Utils from "../utils";
+import PokemonData from "../system/pokemon-data";
+import i18next from "i18next";
+import {Button} from "../enums/buttons";
+import { BattleType } from "../battle";
+import { TrainerVariant } from "../field/trainer";
+import { Challenges } from "#enums/challenges";
+import { getLuckString, getLuckTextTint } from "../modifier/modifier-type";
+import RoundRectangle from "phaser3-rex-plugins/plugins/roundrectangle.js";
+import { Type, getTypeRgb } from "../data/type";
+import { starterPassiveAbilities } from "../data/pokemon-species";
+import { getNatureStatMultiplier, getNatureName } from "../data/nature";
+import { allAbilities } from "../data/ability";
+import { getVariantTint } from "#app/data/variant";
+import { PokemonHeldItemModifier } from "../modifier/modifier";
+
+/*
+enum Page {
+ GENERAL,
+ STATS,
+ HALL_OF_FAME
+}
+*/
+
+export enum RunVictory {
+ DEFEATED,
+ VICTORY
+}
+
+export default class GameInfoUiHandler extends UiHandler {
+ private runInfo: SessionSaveData;
+ private victory: Boolean;
+
+ private gameStatsContainer: Phaser.GameObjects.Container;
+ private statsContainer: Phaser.GameObjects.Container;
+
+ private runInfoContainer: Phaser.GameObjects.Container;
+ private partyContainer: Phaser.GameObjects.Container;
+ private statsBgWidth: integer;
+ private partyContainerHeight: integer;
+ private partyContainerWidth: integer;
+
+ private hallofFameContainer: Phaser.GameObjects.Container;
+
+ private partyInfo: Phaser.GameObjects.Container[];
+
+ private statValues: Phaser.GameObjects.Text[];
+
+ constructor(scene: BattleScene) {
+ super(scene, Mode.RUN_INFO);
+ }
+
+ setup() {
+
+ //const ui = this.getUi();
+ //const page = 0;
+
+ this.gameStatsContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1);
+
+ this.gameStatsContainer.setVisible(false);
+ }
+
+ show(args: any[]): boolean {
+ super.show(args);
+
+ this.statsBgWidth = ((this.scene.game.canvas.width / 6) - 2) / 3;
+
+ this.runInfoContainer = this.scene.add.container(0, 24);
+
+ this.partyContainer = this.scene.add.container(this.statsBgWidth-10, 24);
+
+ this.setCursor(0);
+
+ const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
+ headerBg.setOrigin(0, 0);
+
+ const headerText = addTextObject(this.scene, 0, 0, i18next.t("runHistory:runInfo"), TextStyle.SETTINGS_LABEL);
+ headerText.setOrigin(0, 0);
+ headerText.setPositionRelative(headerBg, 8, 4);
+ this.gameStatsContainer.add(headerBg);
+ this.gameStatsContainer.add(headerText);
+
+
+ this.partyContainerWidth = (this.statsBgWidth*2)+10;
+ this.partyContainerHeight = (this.scene.game.canvas.height / 6) - 25;
+ const partyInfoWindow = addWindow(this.scene, 0, 0, (this.statsBgWidth*2)+10, (this.scene.game.canvas.height / 6) - 25);
+ partyInfoWindow.setOrigin(0,0);
+
+ this.partyContainer.add(partyInfoWindow);
+
+ const runInfoWindow = addWindow(this.scene, 0, 0, this.statsBgWidth-10, (this.scene.game.canvas.height / 6) - 25);
+ runInfoWindow.setOrigin(0, 0);
+ this.runInfoContainer.add(runInfoWindow);
+
+ const run = args[0];
+ const runHistoryOrigin = args[1] ? true : false;
+
+ this.runInfo = this.scene.gameData.parseSessionData(JSON.stringify(run.entry));
+ this.victory = run.victory;
+
+ this.parseRunInfo(this.runInfo, runHistoryOrigin, run.victory);
+
+ const partyData = runHistoryOrigin ? this.runInfo.party : {};
+ this.parsePartyInfo(partyData);
+
+ this.gameStatsContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains);
+
+
+ this.getUi().bringToTop(this.gameStatsContainer);
+ this.gameStatsContainer.setVisible(true);
+
+
+ this.setCursor(0);
+
+ this.getUi().add(this.gameStatsContainer);
+ //this.updateStats();
+
+ this.getUi().hideTooltip();
+
+ return true;
+ }
+
+ async parseRunInfo(runData:any, runHistoryOrigin: boolean, runResult: boolean = false) {
+ const genInfoText = addBBCodeTextObject(this.scene, 6, 18, "", TextStyle.WINDOW, {fontSize : "55px"});
+ if (runHistoryOrigin) {
+ const runResultText = addTextObject(this.scene, 6, 3, `${(runResult ? i18next.t("runHistory:victory") : i18next.t("runHistory:defeated")+" - Wave "+runData.waveIndex)}`, TextStyle.WINDOW, {fontSize : "65px"});
+ runResultText.appendText(new Date(runData.timestamp).toLocaleString());
+ this.runInfoContainer.add(runResultText);
+ }
+ genInfoText.appendText(i18next.t("runHistory:mode")+": ");
+ switch (runData.gameMode) {
+ case GameModes.DAILY:
+ genInfoText.appendText(`${i18next.t("gameMode:dailyRun")}`, false);
+ break;
+ case GameModes.SPLICED_ENDLESS:
+ genInfoText.appendText(`${i18next.t("gameMode:endlessSpliced")}`, false);
+ break;
+ case GameModes.CHALLENGE:
+ genInfoText.appendText(`${i18next.t("gameMode:challenge")}`, false);
+ genInfoText.appendText(`\t\t${i18next.t("runHistory:challengeRules")}: `);
+ const runChallenges = runData.challenges;
+ const rules = [];
+ for (let i = 0; i < runChallenges.length; i++) {
+ if (runChallenges[i].id === Challenges.SINGLE_GENERATION && runChallenges[i].value !== 0) {
+ rules.push(i18next.t(`runHistory:challengeMonoGen${runChallenges[i].value}` as const));
+ } else if (runChallenges[i].id === Challenges.SINGLE_TYPE && runChallenges[i].value !== 0) {
+ rules.push(i18next.t(`pokemonInfo:Type.${Type[runChallenges[i].value-1]}` as const));
+ }
+ }
+ if (rules) {
+ for (let i = 0; i < rules.length; i++) {
+ if (i > 0) {
+ genInfoText.appendText(" + ", false);
+ }
+ genInfoText.appendText(rules[i], false);
+ }
+ }
+ break;
+ case GameModes.ENDLESS:
+ genInfoText.appendText(`${i18next.t("gameMode:endless")}`, false);
+ break;
+ case GameModes.CLASSIC:
+ genInfoText.appendText(`${i18next.t("gameMode:classic")}`, false);
+ break;
+ }
+
+ genInfoText.appendText(`${i18next.t("runHistory:money")}: ${Utils.formatLargeNumber(runData.money, 1000)}`);
+
+ const luckValue = Phaser.Math.Clamp(runData.party.map(p => p.toPokemon(this.scene).getLuck()).reduce((total: integer, value: integer) => total += value, 0), 0, 14);
+ if (luckValue < 14) {
+ const luckTextTint = "[color=#"+(getLuckTextTint(luckValue)).toString(16)+"]";
+ genInfoText.appendText(`${luckTextTint}${i18next.t("runHistory:luck")}: ${getLuckString(luckValue)}[/color]`);
+ } else {
+ const sssLuckText = addTextObject(this.scene, 0, 0, `${i18next.t("runHistory:luck")}: ${getLuckString(luckValue)}`, TextStyle.WINDOW, {fontSize: "55px"});
+ sssLuckText.setTint(0xffef5c, 0x47ff69, 0x6b6bff, 0xff6969);
+ sssLuckText.setPosition(6, 67);
+ this.runInfoContainer.add(sssLuckText);
+ }
+
+ if (runHistoryOrigin && !runResult) {
+ const enemyContainer = this.scene.add.container(8, -42);
+ //Wild - Single and Doubles
+ if (runData.battleType === BattleType.WILD) {
+ runData.enemyParty.forEach((enemyData, e) => {
+ const enemyIconContainer = this.scene.add.container(12+(e*24),63);
+ enemyIconContainer.setScale(0.75);
+ const bossStatus = enemyData.boss;
+ enemyData.boss = false;
+ const enemy = enemyData.toPokemon(this.scene);
+ const enemyIcon = this.scene.addPokemonIcon(enemy, 0, 0, 0, 0);
+ const enemyLevel = addTextObject(this.scene, 32, 24, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, bossStatus ? TextStyle.PARTY_RED : TextStyle.PARTY, { fontSize: "44px", color: "#f8f8f8" });
+ enemyLevel.setShadow(0, 0, null);
+ enemyLevel.setStroke("#424242", 14);
+ enemyLevel.setOrigin(1, 0);
+ enemyIconContainer.add(enemyIcon);
+ enemyIconContainer.add(enemyLevel);
+ enemyContainer.add(enemyIconContainer);
+ enemy.destroy();
+ });
+ genInfoText.setPosition(6,38);
+ //Trainer - Single and Double
+ } else if (runData.battleType === BattleType.TRAINER) {
+ const tObj = runData.trainer.toTrainer(this.scene);
+ const tObjSpriteKey = tObj.config.getSpriteKey(runData.trainer.variant === TrainerVariant.FEMALE, false);
+ const tObjSprite = this.scene.add.sprite(3, 75, tObjSpriteKey);
+ if (runData.trainer.variant === TrainerVariant.DOUBLE) {
+ const doubleContainer = this.scene.add.container(5, 80);
+ tObjSprite.setPosition(-3, -3);
+ const tObjPartnerSpriteKey = tObj.config.getSpriteKey(true, true);
+ const tObjPartnerSprite = this.scene.add.sprite(5, -3, tObjPartnerSpriteKey);
+ tObjPartnerSprite.setScale(0.20);
+ tObjSprite.setScale(0.20);
+ doubleContainer.add(tObjSprite);
+ doubleContainer.add(tObjPartnerSprite);
+ enemyContainer.add(doubleContainer);
+ } else {
+ tObjSprite.setScale(0.25, 0.25);
+ tObjSprite.setPosition(6, 82);
+ enemyContainer.add(tObjSprite);
+ }
+
+ const teraPokemon = {};
+ runData.enemyModifiers.forEach((m) => {
+ if (m.className === "TerastallizeModifier") {
+ teraPokemon[m.args[0]] = m.args[1];
+ }
+ });
+
+ runData.enemyParty.forEach((enemyData, e) => {
+ const pokemonRowHeight = Math.floor(e/3);
+ const enemyIconContainer = this.scene.add.container(8+((e%3)*12), 66);
+ enemyIconContainer.setScale(0.5);
+ const isBoss = enemyData.boss;
+ enemyData.boss = false;
+ const enemy = enemyData.toPokemon(this.scene);
+ const enemyIcon = this.scene.addPokemonIcon(enemy, 0, 0, 0, 0);
+ const enemySprite1 = enemyIcon.list[0] as Phaser.GameObjects.Sprite;
+ const enemySprite2 = (enemyIcon.list.length > 1) ? enemyIcon.list[1] as Phaser.GameObjects.Sprite : null;
+ if (teraPokemon[enemyData.id]) {
+ const teraTint = getTypeRgb(teraPokemon[enemyData.id]);
+ const teraColor = new Phaser.Display.Color(teraTint[0], teraTint[1], teraTint[2]);
+ enemySprite1.setTint(teraColor.color);
+ if (enemySprite2) {
+ enemySprite2.setTint(teraColor.color);
+ }
+ }
+ enemyIcon.setPosition(34+(24 * (e%3)), 0+(35*pokemonRowHeight));
+ const enemyLevel = addTextObject(this.scene, (26*(e%3))+44, 26+(35*pokemonRowHeight), `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(enemy.level, 1000)}`, isBoss ? TextStyle.PARTY_RED : TextStyle.PARTY, { fontSize: "54px" });
+ enemyLevel.setShadow(0, 0, null);
+ enemyLevel.setStroke("#424242", 14);
+ enemyLevel.setOrigin(1, 0);
+
+ enemyIconContainer.add(enemyIcon);
+ enemyIconContainer.add(enemyLevel);
+ enemyContainer.add(enemyIconContainer);
+ enemy.destroy();
+ });
+
+ if (runData.enemyParty.length > 3) {
+ genInfoText.setPosition(6,52);
+ } else {
+ genInfoText.setPosition(6,40);
+ }
+ }
+ this.runInfoContainer.add(enemyContainer);
+ }
+
+ if (runData.modifiers.length) {
+ genInfoText.appendText((luckValue < 14) ? i18next.t("runHistory:playerItems")+": " : "\n"+i18next.t("runHistory:playerItems")+": ");
+ const modifiersModule = await import("../modifier/modifier");
+
+ let visibleModifierIndex = 0;
+
+ const modifierIconsContainer = this.scene.add.container(8, 65);
+ modifierIconsContainer.setScale(0.45);
+ for (const m of runData.modifiers) {
+ const modifier = m.toModifier(this.scene, modifiersModule[m.className]);
+ if (modifier instanceof PokemonHeldItemModifier) {
+ continue;
+ }
+ const item = this.scene.add.sprite(0, 12, "items");
+ item.setFrame(modifier.type.iconImage);
+
+ item.setOrigin(0, 0.5);
+ const rowHeightModifier = Math.floor(visibleModifierIndex/7);
+ item.setPosition(24 * (visibleModifierIndex%7), 0+(35*rowHeightModifier));
+ const itemStackCount = addTextObject(this.scene, (24*(visibleModifierIndex%7))+22, 8+(35*rowHeightModifier), modifier.stackCount, TextStyle.PARTY, {fontSize:"64px"});
+ modifierIconsContainer.add(item);
+ modifierIconsContainer.add(itemStackCount);
+ if (++visibleModifierIndex === 20) {
+ const maxItems = addTextObject(this.scene, 45, 90, "+", TextStyle.WINDOW);
+ maxItems.setPositionRelative(modifierIconsContainer, 70, 45);
+ this.runInfoContainer.add(maxItems);
+ break;
+ }
+ }
+ if (runData.gameMode === GameModes.CHALLENGE) {
+ modifierIconsContainer.setPositionRelative(genInfoText, 2, 55);
+ } else {
+ modifierIconsContainer.setPositionRelative(genInfoText, 2, 55);
+ }
+
+ this.runInfoContainer.add(modifierIconsContainer);
+ }
+
+ this.runInfoContainer.add(genInfoText);
+ this.gameStatsContainer.add(this.runInfoContainer);
+
+ }
+
+ parsePartyInfo(party: any) {
+
+ const windowHeight = ((this.scene.game.canvas.height / 6) - 23)/3;
+
+ const infoWidth = (this.statsBgWidth/2);
+
+ const pokemonPos = [[infoWidth+4, 28], [(infoWidth*3)+5, 28], [infoWidth+4, 78], [(infoWidth*3)+5, 78], [infoWidth+4, 128], [(infoWidth*3)+5, 128]];
+ party.forEach((p: PokemonData, i: integer) => {
+ const pokemonInfoWindow = new RoundRectangle(this.scene, 0, 0, infoWidth*2, windowHeight-3, 3);
+ pokemonInfoWindow.setStrokeStyle(1, 0x4b4b4b, 0.85);
+ //const pokemonSpriteWindow = this.scene.add.rectangle(0, 0, 21, 21, 0xFFFFFF, 0.4);
+
+ const pokemon = p.toPokemon(this.scene);
+ const pokemonInfoContainer = this.scene.add.container(pokemonPos[i][0], pokemonPos[i][1]);
+ pokemonInfoWindow.setStrokeStyle(1, 0x4b4b4b, 0.95);
+
+ const types = pokemon.getTypes();
+ let typeColor = getTypeRgb(types[0]);
+ const type1Color = new Phaser.Display.Color(typeColor[0], typeColor[1], typeColor[2]);
+
+ const bgColor = type1Color.clone().darken(45);
+ pokemonInfoWindow.setFillStyle(bgColor.color);
+ //pokemonInfoWindow.setBlendMode(Phaser.BlendModes.MULTIPLY);
+
+ const iconContainer = this.scene.add.container(-55, -29);
+ //pokemonSpriteWindow.setOrigin(-0.3, -0.25);
+ const icon = this.scene.addPokemonIcon(pokemon, 0, 0, 0, 0);
+ icon.setScale(0.75);
+ icon.setPosition(14, 5.5);
+ //const spriteAnimKey = icon.list[0].anims.key;
+ typeColor = types[1] ? getTypeRgb(types[1]) : null;
+ const type2Color = typeColor ? new Phaser.Display.Color(typeColor[0], typeColor[1], typeColor[2]) : null;
+ const sprite1 = icon.list[0] as Phaser.GameObjects.Sprite;
+ const sprite2 = (icon.list.length > 1) ? icon.list[1] as Phaser.GameObjects.Sprite : null;
+ if (type2Color && !pokemon.fusionSpecies) {
+ sprite1.preFX.addShadow(-1, -1, 0.1, 1, type1Color.color);
+ sprite1.preFX.addGlow(type2Color.color);
+ //pokemonSpriteWindow.setFillStyle(type2Color.color, 0.7);
+ } else if (type2Color && pokemon.fusionSpecies) {
+ sprite1.preFX.addShadow(-1, -1, 0.1, 1, type2Color.color);
+ sprite1.preFX.addGlow(type1Color.color);
+ sprite2.preFX.addShadow(-1, -1, 0.1, 1, type1Color.color);
+ sprite2.preFX.addGlow(type2Color.color);
+ } else {
+ sprite1.preFX.addShadow(-1, -1, 0.1, 1, type1Color.darken(10).color);
+ sprite1.preFX.addGlow(type1Color.color);
+ if (pokemon.fusionSpecies) {
+ sprite2.preFX.addShadow(-1, -1, 0.1, 1, type1Color.color);
+ sprite2.preFX.addGlow(type1Color.color);
+ }
+ }
+ //pokemonSpriteWindow.setPosition(-2,1.5);
+ //icon.add(pokemonSpriteWindow);
+ this.getUi().bringToTop(icon);
+
+ const textContainer = this.scene.add.container(-26, -25);
+ const textContainerFontSize = "34px";
+ const pSpecies = pokemon.species;
+ const pNature = getNatureName(pokemon.nature);
+ const pName = pokemon.fusionSpecies ? pokemon.name : pSpecies.name;
+ const textNameNatureLevel = addTextObject(this.scene, -2, 1, `${pName} - ${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatFancyLargeNumber(pokemon.level, 1)} - ${pNature}`, TextStyle.SUMMARY, { fontSize: textContainerFontSize, color: "#f8f8f8" });
+ textContainer.add(textNameNatureLevel);
+
+ const pPassiveInfo = pokemon.passive ? `${i18next.t("starterSelectUiHandler:passive")+" "+allAbilities[starterPassiveAbilities[pSpecies.speciesId]].name}` : "";
+ const pHasHA = (pSpecies.abilityHidden === pSpecies.getAbility(pokemon.abilityIndex)) ? ["[color=#e8e8a8]","[/color]"] : ["",""];
+ const abilityInd = pokemon.fusionSpecies ? pokemon.fusionAbilityIndex : pokemon.abilityIndex;
+ const pAbilityInfo = i18next.t("starterSelectUiHandler:ability")+" "+pHasHA[0] + allAbilities[pSpecies.getAbility(abilityInd)].name + pHasHA[1];
+ const textAbility = addBBCodeTextObject(this.scene, -2, 6, `${pAbilityInfo}`, TextStyle.SUMMARY, { fontSize: textContainerFontSize });
+ textContainer.add(textAbility);
+ const textPassive = addBBCodeTextObject(this.scene, -2, 11, pPassiveInfo, TextStyle.SUMMARY, {fontSize: textContainerFontSize});
+ textContainer.add(textPassive);
+
+ const pStats = [];
+ pokemon.stats.forEach((element) => pStats.push(Utils.formatFancyLargeNumber(element,1)));
+ const currentLanguage = i18next.resolvedLanguage;
+ for (let i = 0; i < pStats.length; i++) {
+ const isMult = getNatureStatMultiplier(pokemon.nature, i);
+ pStats[i] = (isMult < 1) ? pStats[i] + "↓" : pStats[i];
+ pStats[i] = (isMult > 1) ? pStats[i] + "↑" : pStats[i];
+ }
+ //Row 1: HP, Atk, Def
+ //Row 2: SpAtk, SpDef, Speed
+ const hp = addBBCodeTextObject(this.scene, 0, 0, i18next.t("pokemonInfo:Stat.HPshortened")+": "+pStats[0], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+ const atk = addBBCodeTextObject(this.scene, 0, 0, i18next.t("pokemonInfo:Stat.ATKshortened")+": "+pStats[1], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+ const def = addBBCodeTextObject(this.scene, 0, 0, i18next.t("pokemonInfo:Stat.DEFshortened")+": "+pStats[2], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+ const spatk = addBBCodeTextObject(this.scene, 0, 0, i18next.t("pokemonInfo:Stat.SPATKshortened")+": "+pStats[3], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+ const spdef = addBBCodeTextObject(this.scene, 0, 0, i18next.t("pokemonInfo:Stat.SPDEFshortened")+": "+pStats[4], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+ const speedLabel = (currentLanguage==="es"||currentLanguage==="pt_BR") ? i18next.t("runHistory:SPDshortened") : i18next.t("pokemonInfo:Stat.SPDshortened");
+ const speed = addBBCodeTextObject(this.scene, 0, 0, speedLabel+": "+pStats[5], TextStyle.SUMMARY, { fontSize: textContainerFontSize, align: "center" });
+
+ Phaser.Actions.GridAlign([hp, atk, def, spatk, spdef, speed], {width:3, height:2, cellWidth:28, cellHeight: 6.25, x: -2, y: 20, position: Phaser.Display.Align.TOP_LEFT});
+ textContainer.add([hp, atk, def, spatk, spdef, speed]);
+
+ if (pokemon.fusionSpecies) {
+ const splicedIcon = this.scene.add.image(0, 0, "icon_spliced");
+ splicedIcon.setScale(0.35);
+ splicedIcon.setOrigin(0, 0);
+ splicedIcon.setPositionRelative(textContainer, 121, 32);
+ iconContainer.add(splicedIcon);
+ this.getUi().bringToTop(splicedIcon);
+ }
+
+ if (pokemon.isShiny()) {
+ const doubleShiny = pokemon.isFusion() && pokemon.shiny && pokemon.fusionShiny;
+
+ const shinyStar = this.scene.add.image(0, 0, `shiny_star_small${doubleShiny ? "_1" : ""}`);
+ shinyStar.setOrigin(0, 0);
+ shinyStar.setScale(0.65);
+ shinyStar.setPositionRelative(textContainer, 127, 32);
+ shinyStar.setTint(getVariantTint(!doubleShiny ? pokemon.getVariant() : pokemon.variant));
+ iconContainer.add(shinyStar);
+ this.getUi().bringToTop(shinyStar);
+
+ if (doubleShiny) {
+ const fusionShinyStar = this.scene.add.image(0, 0, "shiny_star_small_2");
+ fusionShinyStar.setOrigin(0, 0);
+ fusionShinyStar.setScale(0.5);
+ fusionShinyStar.setPosition(shinyStar.x, shinyStar.y);
+ fusionShinyStar.setTint(getVariantTint(pokemon.fusionVariant));
+ iconContainer.add(fusionShinyStar);
+ this.getUi().bringToTop(fusionShinyStar);
+ }
+ }
+
+ const pokemonMoveset = pokemon.getMoveset();
+ const movesetContainer = this.scene.add.container(5.5, -28);
+ const pokemonMoveBgs = [];
+ const pokemonMoveLabels = [];
+ const movePos = [[-6.5,35.5],[37,35.5],[-6.5,43.5],[37,43.5]];
+ for (let m = 0; m < pokemonMoveset.length; m++) {
+ const moveContainer = this.scene.add.container(movePos[m][0], movePos[m][1]);
+ moveContainer.setScale(0.5);
+
+ const moveBg = this.scene.add.nineslice(0, 0, "type_bgs", "unknown", 85, 15, 2, 2, 2, 2);
+ moveBg.setOrigin(1, 0);
+
+ const moveLabel = addTextObject(this.scene, -moveBg.width / 2, 2, "-", TextStyle.PARTY);
+ moveLabel.setOrigin(0.5, 0);
+ moveLabel.setName("text-move-label");
+
+ pokemonMoveBgs.push(moveBg);
+ pokemonMoveLabels.push(moveLabel);
+
+ moveContainer.add(moveBg);
+ moveContainer.add(moveLabel);
+
+ movesetContainer.add(moveContainer);
+
+ const move = m < pokemonMoveset.length ? pokemonMoveset[m].getMove() : null;
+ pokemonMoveBgs[m].setFrame(Type[move ? move.type : Type.UNKNOWN].toString().toLowerCase());
+ pokemonMoveLabels[m].setText(move ? move.name : "-");
+ }
+
+ pokemonInfoContainer.add(pokemonInfoWindow);
+ iconContainer.add(icon);
+ pokemonInfoContainer.add(iconContainer);
+ pokemonInfoContainer.add(movesetContainer);
+ pokemonInfoContainer.add(textContainer);
+
+ this.partyContainer.add(pokemonInfoContainer);
+ pokemon.destroy();
+ });
+ this.gameStatsContainer.add(this.partyContainer);
+ }
+
+ processInput(button: Button): boolean {
+ const ui = this.getUi();
+
+ let success = false;
+ const error = false;
+
+ if (button === Button.CANCEL) {
+ success = true;
+ this.runInfoContainer.removeAll(true);
+ this.partyContainer.removeAll(true);
+ this.gameStatsContainer.removeAll(true);
+ super.clear();
+ this.gameStatsContainer.setVisible(false);
+ ui.revertMode();
+ } else {
+ switch (button) {
+ case Button.DOWN:
+ case Button.UP:
+ break;
+ }
+ }
+
+ if (success) {
+ ui.playSelect();
+ } else if (error) {
+ ui.playError();
+ }
+ return success || error;
+ }
+}
+
diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts
index 9849e1c03695..25d1060f23e6 100644
--- a/src/ui/starter-select-ui-handler.ts
+++ b/src/ui/starter-select-ui-handler.ts
@@ -39,7 +39,6 @@ import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import {Button} from "#enums/buttons";
import { EggSourceType } from "#app/enums/egg-source-types.js";
-import AwaitableUiHandler from "./awaitable-ui-handler";
export type StarterSelectCallback = (starters: Starter[]) => void;
@@ -225,9 +224,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private genMode: boolean;
private statsMode: boolean;
- private starterIconsCursorXOffset: number = -2;
- private starterIconsCursorYOffset: number = 1;
- private starterIconsCursorIndex: number;
private dexAttrCursor: bigint = 0n;
private abilityCursor: integer = -1;
private natureCursor: integer = -1;
@@ -264,7 +260,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private starterIcons: Phaser.GameObjects.Sprite[];
private genCursorObj: Phaser.GameObjects.Image;
private genCursorHighlightObj: Phaser.GameObjects.Image;
- private starterIconsCursorObj: Phaser.GameObjects.Image;
private valueLimitLabel: Phaser.GameObjects.Text;
private startCursorObj: Phaser.GameObjects.NineSlice;
private starterValueLabels: Phaser.GameObjects.Text[];
@@ -441,12 +436,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.genCursorObj.setOrigin(0, 0);
this.starterSelectContainer.add(this.genCursorObj);
- this.starterIconsCursorObj = this.scene.add.image(this.genCursorObj.x, 64, "select_gen_cursor");
- this.starterIconsCursorObj.setName("starter-icons-cursor");
- this.starterIconsCursorObj.setVisible(false);
- this.starterIconsCursorObj.setOrigin(0, 0);
- this.starterSelectContainer.add(this.starterIconsCursorObj);
-
this.valueLimitLabel = addTextObject(this.scene, 124, 150, "0/10", TextStyle.TOOLTIP_CONTENT);
this.valueLimitLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(this.valueLimitLabel);
@@ -1064,7 +1053,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.toggleStatsMode(false);
success = true;
} else if (this.starterCursors.length) {
- this.popStarter(this.starterCursors.length - 1);
+ this.popStarter();
success = true;
this.updateInstructions();
} else {
@@ -1078,9 +1067,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.scene.getCurrentPhase().end();
success = true;
}
- } else if (this.startCursorObj.visible) { // this checks to see if the start button is selected
- const genStarters = this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAll().length;
- const rows = Math.ceil(genStarters / 9);
+ } else if (this.startCursorObj.visible) {
switch (button) {
case Button.ACTION:
if (this.tryStart(true)) {
@@ -1090,16 +1077,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
break;
case Button.UP:
- this.startCursorObj.setVisible(false);
- if (this.starterCursors.length > 0) {
- this.starterIconsCursorIndex = this.starterCursors.length - 1;
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
- } else {
- this.setGenMode(true);
- }
- success = true;
- break;
- case Button.DOWN:
this.startCursorObj.setVisible(false);
this.setGenMode(true);
success = true;
@@ -1107,37 +1084,27 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
case Button.LEFT:
this.startCursorObj.setVisible(false);
this.setGenMode(false);
- this.setCursor(genStarters - 1);
+ this.setCursor(this.cursor + 8);
success = true;
break;
case Button.RIGHT:
this.startCursorObj.setVisible(false);
this.setGenMode(false);
- this.setCursor((rows - 1) * 9);
success = true;
break;
}
- } else if (this.genMode && this.genCursorObj.visible) { // this checks to see if the generation selection icons are selected
+ } else if (this.genMode) {
switch (button) {
case Button.UP:
- if (this.genCursor > 0) {
+ if (this.genCursor) {
success = this.setCursor(this.genCursor - 1);
- } else {
- this.startCursorObj.setVisible(true);
- this.setGenMode(true);
- success = true;
}
break;
case Button.DOWN:
if (this.genCursor < 2) {
success = this.setCursor(this.genCursor + 1);
} else {
- if (this.starterCursors.length === 0) {
- this.startCursorObj.setVisible(true);
- } else {
- this.starterIconsCursorIndex = 0;
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
- }
+ this.startCursorObj.setVisible(true);
this.setGenMode(true);
success = true;
}
@@ -1151,72 +1118,66 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
break;
}
} else {
- /**
- * This code generates the menu for a pokemon when you press the action button
- * This works in modules; it does a check for each option to see if it's valid, and if so, will add that option to the menu
- * As an example, if you try to add an invalid pokemon, the "Add to Party" option won't show up
- * But if you can still use candies or change natures, those menu items will be added
- * Once it's all done, it displays the menu for you
- **/
if (button === Button.ACTION) {
if (!this.speciesStarterDexEntry?.caughtAttr) {
error = true;
- } else if (this.starterCursors.length < 6) { // checks to see you have less than 6 pokemon in your party
- let pokemonGen;
- let pokemonCursor;
- // this gets the correct generation and pokemon cursor depending on whether you're in the starter screen or the party icons
- if (!this.starterIconsCursorObj.visible) {
- pokemonGen = this.getGenCursorWithScroll();
- pokemonCursor = this.cursor;
- } else {
- pokemonGen = this.starterGens[this.starterIconsCursorIndex];
- pokemonCursor = this.starterCursors[this.starterIconsCursorIndex];
- }
- const ui = this.getUi();
- let options = [];
-
- const [isDupe, removeIndex]: [boolean, number] = this.isInParty(pokemonGen, pokemonCursor); // checks to see if the pokemon is a duplicate; if it is, returns the index that will be removed
-
- const species = this.genSpecies[pokemonGen][pokemonCursor];
-
- const isPartyValid = this.isPartyValid();
- const isValidForChallenge = new Utils.BooleanHolder(true);
- if (isPartyValid) {
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true)), this.starterGens.length + 1);
- } else {
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true)), this.starterGens.length + 1, false, false);
- }
- const currentPartyValue = this.starterGens.reduce((total: number, gen: number, i: number) => total += this.scene.gameData.getSpeciesStarterValue(this.genSpecies[gen][this.starterCursors[i]].speciesId), 0);
- const newCost = this.scene.gameData.getSpeciesStarterValue(species.speciesId);
- if (!isDupe && isValidForChallenge.value && currentPartyValue + newCost <= this.getValueLimit()) { // this checks to make sure the pokemon doesn't exist in your party, it's valid for the challenge and that it won't go over the cost limit; if it meets all these criteria it will add it to your party
- options = [
- {
- label: i18next.t("starterSelectUiHandler:addToParty"),
- handler: () => {
- ui.setMode(Mode.STARTER_SELECT);
-
- if (!isDupe && isValidForChallenge.value && this.tryUpdateValue(this.scene.gameData.getSpeciesStarterValue(species.speciesId), true)) {
- this.addToParty(species, pokemonGen, pokemonCursor);
- ui.playSelect();
- } else {
- ui.playError(); // this should be redundant as there is now a trigger for when a pokemon can't be added to party
- }
- return true;
- },
- overrideSound: true
- }];
- } else if (isDupe) { // if it already exists in your party, it will give you the option to remove from your party
- options = [{
- label: i18next.t("starterSelectUiHandler:removeFromParty"),
+ } else if (this.starterCursors.length < 6) {
+ const options = [
+ {
+ label: i18next.t("starterSelectUiHandler:addToParty"),
handler: () => {
- this.popStarter(removeIndex);
ui.setMode(Mode.STARTER_SELECT);
- return true;
- }
- }];
- }
+ let isDupe = false;
+ for (let s = 0; s < this.starterCursors.length; s++) {
+ if (this.starterGens[s] === this.getGenCursorWithScroll() && this.starterCursors[s] === this.cursor) {
+ isDupe = true;
+ break;
+ }
+ }
+ const species = this.genSpecies[this.getGenCursorWithScroll()][this.cursor];
+
+ const isValidForChallenge = new Utils.BooleanHolder(true);
+ Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), this.starterGens.length);
+
+ if (!isDupe && isValidForChallenge.value && this.tryUpdateValue(this.scene.gameData.getSpeciesStarterValue(species.speciesId))) {
+ const cursorObj = this.starterCursorObjs[this.starterCursors.length];
+ cursorObj.setVisible(true);
+ cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
+ const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor);
+ this.starterIcons[this.starterCursors.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
+ this.starterIcons[this.starterCursors.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant));
+ this.checkIconId(this.starterIcons[this.starterCursors.length], species, props.female, props.formIndex, props.shiny, props.variant);
+ this.starterGens.push(this.getGenCursorWithScroll());
+ this.starterCursors.push(this.cursor);
+ this.starterAttr.push(this.dexAttrCursor);
+ this.starterAbilityIndexes.push(this.abilityCursor);
+ this.starterNatures.push(this.natureCursor as unknown as Nature);
+ this.starterMovesets.push(this.starterMoveset.slice(0) as StarterMoveset);
+ if (this.speciesLoaded.get(species.speciesId)) {
+ getPokemonSpeciesForm(species.speciesId, props.formIndex).cry(this.scene);
+ }
+ if (this.starterCursors.length === 6 || this.value === this.getValueLimit()) {
+ this.tryStart();
+ }
+ this.updateInstructions();
+
+ /**
+ * If the user can't select a pokemon anymore,
+ * go to start button.
+ */
+ if (!this.canAddParty) {
+ this.startCursorObj.setVisible(true);
+ this.setGenMode(true);
+ }
- options.push( // this shows the IVs for the pokemon
+ ui.playSelect();
+ } else {
+ ui.playError();
+ }
+ return true;
+ },
+ overrideSound: true
+ },
{
label: i18next.t("starterSelectUiHandler:toggleIVs"),
handler: () => {
@@ -1224,8 +1185,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.setMode(Mode.STARTER_SELECT);
return true;
}
- });
- if (this.speciesStarterMoves.length > 1) { // this lets you change the pokemon moves
+ }
+ ];
+ if (this.speciesStarterMoves.length > 1) {
const showSwapOptions = (moveset: StarterMoveset) => {
ui.setMode(Mode.STARTER_SELECT).then(() => {
ui.showText(i18next.t("starterSelectUiHandler:selectMoveSwapOut"), null, () => {
@@ -1321,8 +1283,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
handler: () => {
// update default nature in starter save data
if (!starterAttributes) {
- starterAttributes =
- this.starterPreferences[this.lastSpecies.speciesId] = {};
+ starterAttributes=
+ this.starterPreferences[this.lastSpecies.speciesId] = {};
}
starterAttributes.nature = n as unknown as integer;
this.clearText();
@@ -1357,7 +1319,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
const candyCount = starterData.candyCount;
const passiveAttr = starterData.passiveAttr;
- if (passiveAttr & PassiveAttr.UNLOCKED) { // this is for enabling and disabling the passive
+ if (passiveAttr & PassiveAttr.UNLOCKED) {
if (!(passiveAttr & PassiveAttr.ENABLED)) {
options.push({
label: i18next.t("starterSelectUiHandler:enablePassive"),
@@ -1380,12 +1342,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
}
}
- const showUseCandies = () => { // this lets you use your candies
+ const showUseCandies = () => {
const options = [];
if (!(passiveAttr & PassiveAttr.UNLOCKED)) {
const passiveCost = getPassiveCandyCount(speciesStarters[this.lastSpecies.speciesId]);
options.push({
-
label: `x${passiveCost} ${i18next.t("starterSelectUiHandler:unlockPassive")} (${allAbilities[starterPassiveAbilities[this.lastSpecies.speciesId]].name})`,
handler: () => {
if (Overrides.FREE_CANDY_UPGRADE_OVERRIDE || candyCount >= passiveCost) {
@@ -1403,8 +1364,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined);
// Update the candy upgrade display
- if (this.isUpgradeIconEnabled()) {
- this.setUpgradeIcon(pokemonCursor);
+ if (this.isUpgradeIconEnabled() ) {
+ this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
@@ -1436,15 +1397,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return this.scene.reset(true);
}
});
- this.updateStarterValueLabel(pokemonCursor);
+ this.updateStarterValueLabel(this.cursor);
this.tryUpdateValue(0);
ui.setMode(Mode.STARTER_SELECT);
this.scene.playSound("buy");
// If the notification setting is set to 'On', update the candy upgrade display
if (this.scene.candyUpgradeNotification === 2) {
- if (this.isUpgradeIconEnabled()) {
- this.setUpgradeIcon(pokemonCursor);
+ if (this.isUpgradeIconEnabled() ) {
+ this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
@@ -1549,7 +1510,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterPreferences[this.lastSpecies.speciesId] = {};
}
switch (button) {
-
case Button.CYCLE_SHINY:
if (this.canCycleShiny) {
const newVariant = props.variant;
@@ -1653,118 +1613,50 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
success = true;
}
break;
-
case Button.UP:
- if (!this.starterIconsCursorObj.visible) {
- if (row) {
- success = this.setCursor(this.cursor - 9);
- } else {
- // when strictly opposite starter based on rows length
- // does not exits, set cursor on the second to last row
- if (this.cursor + (rows - 1) * 9 > genStarters - 1) {
- success = this.setCursor(this.cursor + (rows - 2) * 9);
- } else {
- success = this.setCursor(this.cursor + (rows - 1) * 9);
- }
- }
+ if (row) {
+ success = this.setCursor(this.cursor - 9);
} else {
- if (this.starterIconsCursorIndex === 0) {
- this.starterIconsCursorObj.setVisible(false);
- this.setSpecies(null);
- this.setGenMode(true);
+ // when strictly opposite starter based on rows length
+ // does not exits, set cursor on the second to last row
+ if (this.cursor + (rows - 1) * 9 > genStarters - 1) {
+ success = this.setCursor(this.cursor + (rows - 2) * 9);
} else {
- this.starterIconsCursorIndex--;
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
+ success = this.setCursor(this.cursor + (rows - 1) * 9);
}
}
break;
case Button.DOWN:
- if (!this.starterIconsCursorObj.visible) {
- if (row < rows - 2 || (row < rows - 1 && this.cursor % 9 <= (genStarters - 1) % 9)) {
- success = this.setCursor(this.cursor + 9);
- } else {
- // if there is no starter below while being on the second to
- // last row, adjust cursor position with one line less
- if (row === rows - 2 && this.cursor + 9 > genStarters - 1) {
- success = this.setCursor(this.cursor - (rows - 2) * 9);
- } else {
- success = this.setCursor(this.cursor - (rows - 1) * 9);
- }
- }
+ if (row < rows - 2 || (row < rows - 1 && this.cursor % 9 <= (genStarters - 1) % 9)) {
+ success = this.setCursor(this.cursor + 9);
} else {
- if (this.starterIconsCursorIndex <= this.starterCursors.length - 2) {
- this.starterIconsCursorIndex++;
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
+ // if there is no starter below while being on the second to
+ // last row, adjust cursor position with one line less
+ if (row === rows - 2 && this.cursor + 9 > genStarters - 1) {
+ success = this.setCursor(this.cursor - (rows - 2) * 9);
} else {
- this.starterIconsCursorObj.setVisible(false);
- this.setSpecies(null);
- this.startCursorObj.setVisible(true);
+ success = this.setCursor(this.cursor - (rows - 1) * 9);
}
}
break;
case Button.LEFT:
- if (!this.starterIconsCursorObj.visible) {
- if (this.cursor % 9 !== 0) {
- success = this.setCursor(this.cursor - 1);
- } else {
- if (this.starterCursors.length === 0) {
- if (row >= Math.min(5, rows - 1)) {
- this.startCursorObj.setVisible(true);
- }
- success = this.setGenMode(true);
- } else {
- if (row >= rows - 1) { // the last row will always go to the starter button
- this.startCursorObj.setVisible(true);
- } else if (row > 2) { // the first three rows will always go to the gen select, so anything else will go to the starterIcons party section
- if (this.starterCursors.length >= row - 2) {
- this.starterIconsCursorIndex = row - 3;
- } else {
- this.starterIconsCursorIndex = this.starterCursors.length - 1;
- }
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
- }
- success = this.setGenMode(true);
- }
- }
+ if (this.cursor % 9) {
+ success = this.setCursor(this.cursor - 1);
} else {
- this.starterIconsCursorObj.setVisible(false);
- this.setGenMode(false);
- const rowToUse = Math.min(this.starterIconsCursorIndex + 3, rows - 1);
- this.setCursor(Math.min((rowToUse * 9) + 8, genStarters - 1));
- success = true;
+ if (row >= Math.min(5, rows - 1)) {
+ this.startCursorObj.setVisible(true);
+ }
+ success = this.setGenMode(true);
}
break;
case Button.RIGHT:
- if (!this.starterIconsCursorObj.visible) {
- if (this.cursor % 9 < (row < rows - 1 ? 8 : (genStarters - 1) % 9)) {
- success = this.setCursor(this.cursor + 1);
- } else {
- if (this.starterCursors.length === 0) {
- if (row >= Math.min(5, rows - 1)) {
- this.startCursorObj.setVisible(true);
- }
- success = this.setGenMode(true);
- } else {
- if (row >= rows - 1) { // the last row will always go to the starter button
- this.startCursorObj.setVisible(true);
- } else if (row > 2) { // the first three rows will always go to the gen select, so anything else will go to the starterIcons party section
- if (this.starterCursors.length >= row - 2) {
- this.starterIconsCursorIndex = row - 3;
- } else {
- this.starterIconsCursorIndex = this.starterCursors.length - 1;
- }
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
- }
- success = this.setGenMode(true);
- }
- }
+ if (this.cursor % 9 < (row < rows - 1 ? 8 : (genStarters - 1) % 9)) {
+ success = this.setCursor(this.cursor + 1);
} else {
- this.starterIconsCursorObj.setVisible(false);
- this.setGenMode(false);
- const rowToUse = Math.min(this.starterIconsCursorIndex + 3, rows - 1);
- this.setCursor(Math.min((rowToUse * 9), genStarters - 1));
- this.setSpecies(this.genSpecies[this.getGenCursorWithScroll()][this.cursor]);
- success = true;
+ if (row >= Math.min(5, rows - 1)) {
+ this.startCursorObj.setVisible(true);
+ }
+ success = this.setGenMode(true);
}
break;
}
@@ -1780,39 +1672,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return success || error;
}
- isInParty(pokemonGen: number, pokemonCursor: number): [boolean, number] {
- let removeIndex = 0;
- let isDupe = false;
- for (let s = 0; s < this.starterCursors.length; s++) {
- if (this.starterGens[s] === pokemonGen && this.starterCursors[s] === pokemonCursor) {
- isDupe = true;
- removeIndex = s;
- break;
- }
- }
- return [isDupe, removeIndex];
- }
-
- addToParty(species: PokemonSpecies, pokemonGen: number, pokemonCursor: number) {
- const cursorObj = this.starterCursorObjs[this.starterCursors.length];
- cursorObj.setVisible(true);
- cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
- const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor);
- this.starterIcons[this.starterCursors.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
- this.starterIcons[this.starterCursors.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant));
- this.checkIconId(this.starterIcons[this.starterCursors.length], species, props.female, props.formIndex, props.shiny, props.variant);
- this.starterGens.push(pokemonGen);
- this.starterCursors.push(pokemonCursor);
- this.starterAttr.push(this.dexAttrCursor);
- this.starterAbilityIndexes.push(this.abilityCursor);
- this.starterNatures.push(this.natureCursor as unknown as Nature);
- this.starterMovesets.push(this.starterMoveset.slice(0) as StarterMoveset);
- if (this.speciesLoaded.get(species.speciesId)) {
- getPokemonSpeciesForm(species.speciesId, props.formIndex).cry(this.scene);
- }
- this.updateInstructions();
- }
-
switchMoveHandler(i: number, newMove: Moves, move: Moves) {
const speciesId = this.lastSpecies.speciesId;
const existingMoveIndex = this.starterMoveset.indexOf(newMove);
@@ -2058,8 +1917,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
setGenMode(genMode: boolean): boolean {
- this.genCursorObj.setVisible(genMode && !(this.startCursorObj.visible || this.starterIconsCursorObj.visible));
- this.cursorObj.setVisible(!genMode && !(this.startCursorObj.visible || this.starterIconsCursorObj.visible));
+ this.genCursorObj.setVisible(genMode && !this.startCursorObj.visible);
+ this.cursorObj.setVisible(!genMode && !this.startCursorObj.visible);
if (genMode !== this.genMode) {
this.genMode = genMode;
@@ -2068,9 +1927,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (genMode) {
this.setSpecies(null);
}
- if (this.starterIconsCursorObj.visible) {
- this.setSpecies(this.genSpecies[this.starterGens[this.starterIconsCursorIndex]][this.starterCursors[this.starterIconsCursorIndex]]);
- }
return true;
}
@@ -2078,17 +1934,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return false;
}
- moveStarterIconsCursor(index: number): void {
- this.starterIconsCursorObj.x = this.starterIcons[index].x + this.starterIconsCursorXOffset;
- this.starterIconsCursorObj.y = this.starterIcons[index].y + this.starterIconsCursorYOffset;
- if (this.starterCursors.length > 0) {
- this.starterIconsCursorObj.setVisible(true);
- this.setSpecies(this.genSpecies[this.starterGens[index]][this.starterCursors[index]]);
- } else {
- this.starterIconsCursorObj.setVisible(false);
- this.setSpecies(null);
- }
- }
+
setSpecies(species: PokemonSpecies) {
this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null;
@@ -2164,7 +2010,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const dexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(this.lastSpecies, false, true);
const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, dexAttr);
const lastSpeciesIcon = (this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies)) as Phaser.GameObjects.Sprite);
- //lastSpeciesIcon.setTexture(this.lastSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant), this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
+ lastSpeciesIcon.setTexture(this.lastSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant), this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
this.checkIconId(lastSpeciesIcon, this.lastSpecies, props.female, props.formIndex, props.shiny, props.variant);
this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE);
@@ -2474,15 +2320,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonSprite.setVisible(!this.statsMode);
});
- if (!this.starterIconsCursorObj.visible) {
- (this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite)
- .setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female, formIndex, shiny, variant));
- this.checkIconId((this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite), species, female, formIndex, shiny, variant);
- } else {
- (this.starterSelectGenIconContainers[this.starterGens[this.starterIconsCursorIndex]].getAt(this.starterCursors[this.starterIconsCursorIndex]) as Phaser.GameObjects.Sprite)
- .setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female, formIndex, shiny, variant));
- this.checkIconId((this.starterSelectGenIconContainers[this.starterGens[this.starterIconsCursorIndex]].getAt(this.starterCursors[this.starterIconsCursorIndex]) as Phaser.GameObjects.Sprite), species, female, formIndex, shiny, variant);
- }
+
+ const isValidForChallenge = new Utils.BooleanHolder(true);
+ Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), this.starterGens.length);
+ const starterSprite = this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite;
+ starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female, formIndex, shiny, variant));
+ starterSprite.setAlpha(isValidForChallenge.value ? 1 : 0.375);
+ this.checkIconId((this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite), species, female, formIndex, shiny, variant);
this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY);
this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE);
this.canCycleAbility = [ abilityAttr & AbilityAttr.ABILITY_1, (abilityAttr & AbilityAttr.ABILITY_2) && species.ability2, abilityAttr & AbilityAttr.ABILITY_HIDDEN ].filter(a => a).length > 1;
@@ -2620,42 +2464,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
}
- popStarter(index: number): void {
- this.starterGens.splice(index, 1);
- this.starterCursors.splice(index, 1);
- this.starterAttr.splice(index, 1);
- this.starterAbilityIndexes.splice(index, 1);
- this.starterNatures.splice(index, 1);
- this.starterMovesets.splice(index, 1);
-
- for (let s = 0; s < this.starterCursors.length; s++) {
- const species = this.genSpecies[this.starterGens[s]][this.starterCursors[s]];
- const currentDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true);
- const props = this.scene.gameData.getSpeciesDexAttrProps(species, currentDexAttr);
- this.starterIcons[s].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
- this.starterIcons[s].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant));
- if (s >= index) {
- this.starterCursorObjs[s].setPosition(this.starterCursorObjs[s + 1].x, this.starterCursorObjs[s + 1].y);
- this.starterCursorObjs[s].setVisible(this.starterCursorObjs[s + 1].visible);
- }
- }
+ popStarter(): void {
+ this.starterGens.pop();
+ this.starterCursors.pop();
+ this.starterAttr.pop();
+ this.starterAbilityIndexes.pop();
+ this.starterNatures.pop();
+ this.starterMovesets.pop();
this.starterCursorObjs[this.starterCursors.length].setVisible(false);
this.starterIcons[this.starterCursors.length].setTexture("pokemon_icons_0");
this.starterIcons[this.starterCursors.length].setFrame("unknown");
-
- if (this.starterIconsCursorObj.visible) {
- if (this.starterIconsCursorIndex === this.starterCursors.length) {
- if (this.starterCursors.length > 0) {
- this.starterIconsCursorIndex--;
- } else {
- this.starterIconsCursorObj.setVisible(false);
- this.setSpecies(null);
- this.setGenMode(true);
- }
- }
- this.moveStarterIconsCursor(this.starterIconsCursorIndex);
- }
-
this.tryUpdateValue();
}
@@ -2685,7 +2503,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterValueLabels[cursor].setShadowColor(this.getTextColor(textStyle, true));
}
- tryUpdateValue(add?: integer, addingToParty?: boolean): boolean {
+ tryUpdateValue(add?: integer): boolean {
const value = this.starterGens.reduce((total: integer, gen: integer, i: integer) => total += this.scene.gameData.getSpeciesStarterValue(this.genSpecies[gen][this.starterCursors[i]].speciesId), 0);
const newValue = value + (add || 0);
const valueLimit = this.getValueLimit();
@@ -2702,13 +2520,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return false;
}
- let isPartyValid: boolean = this.isPartyValid(); // this checks to see if the party is valid
- if (addingToParty) { // this does a check to see if the pokemon being added is valid; if so, it will update the isPartyValid boolean
- const isNewPokemonValid = new Utils.BooleanHolder(true);
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.genSpecies[this.getGenCursorWithScroll()][this.cursor], isNewPokemonValid, this.scene.gameData.getSpeciesDexAttrProps(this.genSpecies[this.getGenCursorWithScroll()][this.cursor], this.scene.gameData.getSpeciesDefaultDexAttr(this.genSpecies[this.getGenCursorWithScroll()][this.cursor], false, true)), this.starterGens.length + (add ? 1 : 0), false, false);
- isPartyValid = isPartyValid || isNewPokemonValid.value;
- }
-
/**
* this loop is used to set the Sprite's alpha value and check if the user can select other pokemon more.
*/
@@ -2727,41 +2538,24 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
* If remainValue greater than or equal pokemon species and the pokemon is legal for this challenge, the user can select.
* so that the alpha value of pokemon sprite set 1.
*
- * However, if isPartyValid is false, that means none of the party members are valid for the run. In this case, we should
- * check the challenge to make sure evolutions and forms aren't being checked for mono type runs.
- * This will let us set the sprite's alpha to show it can't be selected
- *
* If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater.
* we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too.
*/
const isValidForChallenge = new Utils.BooleanHolder(true);
- if (isPartyValid) { // we have two checks here - one for the party being valid and one for not. This comes from mono type challenges - if the party is valid it will check pokemon's evolutions and forms, and if it's not valid it won't check their evolutions and forms
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.genSpecies[g][s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.genSpecies[g][s], this.scene.gameData.getSpeciesDefaultDexAttr(this.genSpecies[g][s], false, true)), this.starterGens.length + (add ? 1 : 0));
- } else {
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.genSpecies[g][s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.genSpecies[g][s], this.scene.gameData.getSpeciesDefaultDexAttr(this.genSpecies[g][s], false, true)), this.starterGens.length + (add ? 1 : 0), false, false);
- }
+ Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.genSpecies[g][s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.genSpecies[g][s], this.scene.gameData.getSpeciesDefaultDexAttr(this.genSpecies[g][s], false, true)), this.starterGens.length + (add ? 1 : 0));
const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge.value;
- const isPokemonInParty = this.isInParty(g, s)[0]; // this will get the valud of isDupe from isInParty. This will let us see if the pokemon in question is in our party already so we don't grey out the sprites if they're invalid
-
- /* This code does a check to tell whether or not a sprite should be lit up or greyed out. There are 3 ways a pokemon's sprite should be lit up:
- * 1) If it's in your party, it's a valid pokemon (i.e. for challenge) and you have enough points to have it
- * 2) If it's in your party, it's not valid (i.e. for challenges), and you have enough points to have it
- * 3) If it's not in your party, but it's a valid pokemon and you have enough points for it
- * Any other time, the sprite should be greyed out.
- * For example, if it's in your party, valid, but costs too much, or if it's not in your party and not valid, regardless of cost
- */
- if (canBeChosen || (isPokemonInParty && remainValue >= speciesStarterValue)) {
+ if (canBeChosen) {
speciesSprite.setAlpha(1);
if (speciesStarterDexEntry?.caughtAttr) {
this.canAddParty = true;
}
} else {
/**
- * If it can't be chosen, the user can't select.
- * so that the alpha value of pokemon sprite set 0.375.
- */
+ * If it can't be chosen, the user can't select.
+ * so that the alpha value of pokemon sprite set 0.375.
+ */
speciesSprite.setAlpha(0.375);
}
}
@@ -2781,58 +2575,37 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const cancel = () => {
ui.setMode(Mode.STARTER_SELECT);
if (!manualTrigger) {
- this.popStarter(this.starterGens.length - 1);
+ this.popStarter();
}
this.clearText();
};
- const canStart = this.isPartyValid();
-
- if (canStart) {
- ui.showText(i18next.t("starterSelectUiHandler:confirmStartTeam"), null, () => {
- ui.setModeWithoutClear(Mode.CONFIRM, () => {
- const startRun = () => {
- this.scene.money = this.scene.gameMode.getStartingMoney();
- ui.setMode(Mode.STARTER_SELECT);
- const thisObj = this;
- const originalStarterSelectCallback = this.starterSelectCallback;
- this.starterSelectCallback = null;
- originalStarterSelectCallback(new Array(this.starterGens.length).fill(0).map(function (_, i) {
- const starterSpecies = thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]];
- return {
- species: starterSpecies,
- dexAttr: thisObj.starterAttr[i],
- abilityIndex: thisObj.starterAbilityIndexes[i],
- passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
- nature: thisObj.starterNatures[i] as Nature,
- moveset: thisObj.starterMovesets[i],
- pokerus: !![0, 1, 2].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
- };
- }));
- };
- startRun();
- }, cancel, null, null, 19);
- });
- } else {
- const handler = this.scene.ui.getHandler() as AwaitableUiHandler;
- handler.tutorialActive = true;
- this.scene.ui.showText(i18next.t("starterSelectUiHandler:invalidParty"), null, () => this.scene.ui.showText(null, 0, () => handler.tutorialActive = false), null, true);
- }
- return true;
- }
+ ui.showText(i18next.t("starterSelectUiHandler:confirmStartTeam"), null, () => {
+ ui.setModeWithoutClear(Mode.CONFIRM, () => {
+ const startRun = () => {
+ this.scene.money = this.scene.gameMode.getStartingMoney();
+ ui.setMode(Mode.STARTER_SELECT);
+ const thisObj = this;
+ const originalStarterSelectCallback = this.starterSelectCallback;
+ this.starterSelectCallback = null;
+ originalStarterSelectCallback(new Array(this.starterGens.length).fill(0).map(function (_, i) {
+ const starterSpecies = thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]];
+ return {
+ species: starterSpecies,
+ dexAttr: thisObj.starterAttr[i],
+ abilityIndex: thisObj.starterAbilityIndexes[i],
+ passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
+ nature: thisObj.starterNatures[i] as Nature,
+ moveset: thisObj.starterMovesets[i],
+ pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
+ };
+ }));
+ };
+ startRun();
+ }, cancel, null, null, 19);
+ });
- /* This block checks to see if your party is valid
- * It checks each pokemon against the challenge - noting that due to monotype challenges it needs to check the pokemon while ignoring their evolutions/form change items
- */
- isPartyValid(): boolean {
- let canStart = false;
- for (let s = 0; s < this.starterGens.length; s++) {
- const isValidForChallenge = new Utils.BooleanHolder(true);
- const species = this.genSpecies[this.starterGens[s]][this.starterCursors[s]];
- Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), this.starterGens.length, false, false);
- canStart = canStart || isValidForChallenge.value;
- }
- return canStart;
+ return true;
}
toggleStatsMode(on?: boolean): void {
@@ -2891,7 +2664,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.blockInput = false;
while (this.starterCursors.length) {
- this.popStarter(this.starterCursors.length - 1);
+ this.popStarter();
}
if (this.statsMode) {
diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts
index f51b20cb140a..ae94951bc4c6 100644
--- a/src/ui/summary-ui-handler.ts
+++ b/src/ui/summary-ui-handler.ts
@@ -6,7 +6,7 @@ import { PlayerPokemon } from "../field/pokemon";
import { getStarterValueFriendshipCap, speciesStarters } from "../data/pokemon-species";
import { argbFromRgba } from "@material/material-color-utilities";
import { Type, getTypeRgb } from "../data/type";
-import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "./text";
+import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag } from "./text";
import Move, { MoveCategory } from "../data/move";
import { getPokeballAtlasKey } from "../data/pokeball";
import { getGenderColor, getGenderSymbol } from "../data/gender";
@@ -23,8 +23,6 @@ import { Ability } from "../data/ability.js";
import i18next from "i18next";
import {modifierSortFunc} from "../modifier/modifier";
import { PlayerGender } from "#enums/player-gender";
-import { getMoveColor } from "./fight-ui-handler";
-import Phaser from "phaser";
enum Page {
@@ -919,25 +917,17 @@ export default class SummaryUiHandler extends UiHandler {
this.moveRowsContainer = this.scene.add.container(0, 0);
this.movesContainer.add(this.moveRowsContainer);
- const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible
-
for (let m = 0; m < 4; m++) {
const move = m < this.pokemon.moveset.length ? this.pokemon.moveset[m] : null;
const moveRowContainer = this.scene.add.container(0, 16 * m);
this.moveRowsContainer.add(moveRowContainer);
- let moveColour = getTextColor(TextStyle.SUMMARY, false, uiTheme);
if (move) {
const typeIcon = this.scene.add.sprite(0, 0, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[move.getMove().type].toLowerCase()); typeIcon.setOrigin(0, 1);
moveRowContainer.add(typeIcon);
- const effectiveColour = getMoveColor(this.pokemon, move);
- if (effectiveColour) {
- moveColour = effectiveColour;
- }
}
const moveText = addTextObject(this.scene, 35, 0, move ? move.getName() : "-", TextStyle.SUMMARY);
- moveText.setColor(moveColour);
moveText.setOrigin(0, 1);
moveRowContainer.add(moveText);
diff --git a/src/ui/ui.ts b/src/ui/ui.ts
index fa7dc9fad9f9..d9a9d67a082e 100644
--- a/src/ui/ui.ts
+++ b/src/ui/ui.ts
@@ -44,9 +44,10 @@ import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-han
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";
import SettingsDisplayUiHandler from "./settings/settings-display-ui-handler";
import SettingsAudioUiHandler from "./settings/settings-audio-ui-handler";
+import RunHistoryUiHandler from "./run-history-ui-handler";
+import RunInfoUiHandler from "./run-info-ui-handler";
import { PlayerGender } from "#enums/player-gender";
import BgmBar from "#app/ui/bgm-bar";
-import MysteryEncounterUiHandler from "./mystery-encounter-ui-handler";
export enum Mode {
MESSAGE,
@@ -74,6 +75,8 @@ export enum Mode {
SETTINGS_KEYBOARD,
KEYBOARD_BINDING,
ACHIEVEMENTS,
+ RUN_HISTORY,
+ RUN_INFO,
GAME_STATS,
VOUCHERS,
EGG_LIST,
@@ -84,8 +87,7 @@ export enum Mode {
SESSION_RELOAD,
UNAVAILABLE,
OUTDATED,
- CHALLENGE_SELECT,
- MYSTERY_ENCOUNTER
+ CHALLENGE_SELECT
}
const transitionModes = [
@@ -117,6 +119,7 @@ const noTransitionModes = [
Mode.GAME_STATS,
Mode.VOUCHERS,
Mode.LOGIN_FORM,
+ Mode.RUN_HISTORY,
Mode.REGISTRATION_FORM,
Mode.LOADING,
Mode.SESSION_RELOAD,
@@ -172,6 +175,8 @@ export default class UI extends Phaser.GameObjects.Container {
new SettingsKeyboardUiHandler(scene),
new KeyboardBindingUiHandler(scene),
new AchvsUiHandler(scene),
+ new RunHistoryUiHandler(scene),
+ new RunInfoUiHandler(scene),
new GameStatsUiHandler(scene),
new VouchersUiHandler(scene),
new EggListUiHandler(scene),
@@ -182,8 +187,7 @@ export default class UI extends Phaser.GameObjects.Container {
new SessionReloadModalUiHandler(scene),
new UnavailableModalUiHandler(scene),
new OutdatedModalUiHandler(scene),
- new GameChallengesUiHandler(scene),
- new MysteryEncounterUiHandler(scene)
+ new GameChallengesUiHandler(scene)
];
}
@@ -458,6 +462,7 @@ export default class UI extends Phaser.GameObjects.Container {
touchControls.dataset.uiMode = Mode[mode];
}
this.getHandler().show(args);
+ console.log(args);
}
resolve();
};
diff --git a/src/utils.ts b/src/utils.ts
index c9fe319ce411..5aa558bae3af 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -527,6 +527,4 @@ export function reverseValueToKeySetting(input) {
return capitalizedWords.join("_");
}
-export function isNullOrUndefined(object: any): boolean {
- return null === object || undefined === object;
-}
+
diff --git a/src/vite.env.d.ts b/src/vite.env.d.ts
index 0fee69c66b29..b588b5b11452 100644
--- a/src/vite.env.d.ts
+++ b/src/vite.env.d.ts
@@ -1,7 +1,6 @@
///
interface ImportMetaEnv {
- readonly VITE_TITLE?: string;
readonly VITE_BYPASS_LOGIN?: string;
readonly VITE_BYPASS_TUTORIAL?: string;
readonly VITE_API_BASE_URL?: string;