From 9701f27c630e9a3cd5c111bc75562cc434519e25 Mon Sep 17 00:00:00 2001 From: Blitzy <118096277+Blitz425@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:05:11 -0600 Subject: [PATCH 01/21] [Bug] [Hotfix] Remove Penny's Extra Zamazenta (#5439) Co-authored-by: damocleas --- package-lock.json | 4 ++-- package.json | 2 +- src/data/trainer-config.ts | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 739ce18496d..4abfe1c0666 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.0", + "version": "1.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.0", + "version": "1.7.1", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 5a191b3ec99..ca9cf8f2b27 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.0", + "version": "1.7.1", "type": "module", "scripts": { "start": "vite", diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index b7d99ad7ef3..a0158f28238 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -2776,11 +2776,6 @@ export const trainerConfigs: TrainerConfigs = { p.generateName(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.ZAMAZENTA ], TrainerSlot.TRAINER, true, p => { - p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.MASTER_BALL; - })) .setInstantTera(0), // Tera Fairy Sylveon [TrainerType.BUCK]: new TrainerConfig(++t).setName("Buck").initForStatTrainer(true) .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.CLAYDOL ], TrainerSlot.TRAINER, true, p => { From 5941cfb001aa7f486184368612afd50ed39ae867 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Fri, 28 Feb 2025 03:49:27 +0100 Subject: [PATCH 02/21] [Bug][Hotfix] Fix bug with transferring all items (#5440) --- package-lock.json | 4 ++-- package.json | 2 +- src/ui/party-ui-handler.ts | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4abfe1c0666..9e2c0d3a61b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.1", + "version": "1.7.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.1", + "version": "1.7.2", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index ca9cf8f2b27..418c22073c3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.1", + "version": "1.7.2", "type": "module", "scripts": { "start": "vite", diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 136f098df7e..0af94053ceb 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -422,7 +422,10 @@ export default class PartyUiHandler extends MessageUiHandler { if (option === PartyOption.TRANSFER) { if (this.transferCursor !== this.cursor) { if (this.transferAll) { - getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor]).forEach((_, i) => (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, i, this.transferQuantitiesMax[i], this.cursor)); + getTransferrableItemsFromPokemon(globalScene.getPlayerParty()[this.transferCursor]).forEach((_, i, array) => { + const invertedIndex = array.length - 1 - i; + (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, invertedIndex, this.transferQuantitiesMax[invertedIndex], this.cursor); + }); } else { (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.transferQuantities[this.transferOptionCursor], this.cursor); } @@ -1187,7 +1190,6 @@ class PartySlot extends Phaser.GameObjects.Container { 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; @@ -1208,6 +1210,10 @@ class PartySlot extends Phaser.GameObjects.Container { } setup(partyUiMode: PartyUiMode, tmMoveId: Moves) { + + const currentLanguage = i18next.resolvedLanguage ?? "en"; + const offsetJa = currentLanguage === "ja"; + const battlerCount = globalScene.currentBattle.getBattlerCount(); const slotKey = `party_slot${this.slotIndex >= battlerCount ? "" : "_main"}`; @@ -1246,15 +1252,15 @@ class PartySlot extends Phaser.GameObjects.Container { nameSizeTest.destroy(); this.slotName = addTextObject(0, 0, displayName, TextStyle.PARTY); - this.slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, this.slotIndex >= battlerCount ? 2 : 10); + this.slotName.setPositionRelative(slotBg, this.slotIndex >= battlerCount ? 21 : 24, (this.slotIndex >= battlerCount ? 2 : 10) + (offsetJa ? 2 : 0)); this.slotName.setOrigin(0, 0); const slotLevelLabel = globalScene.add.image(0, 0, "party_slot_overlay_lv"); - slotLevelLabel.setPositionRelative(this.slotName, 8, 12); + slotLevelLabel.setPositionRelative(slotBg, (this.slotIndex >= battlerCount ? 21 : 24) + 8, (this.slotIndex >= battlerCount ? 2 : 10) + 12); slotLevelLabel.setOrigin(0, 0); const slotLevelText = addTextObject(0, 0, this.pokemon.level.toString(), this.pokemon.level < globalScene.getMaxExpLevel() ? TextStyle.PARTY : TextStyle.PARTY_RED); - slotLevelText.setPositionRelative(slotLevelLabel, 9, 0); + slotLevelText.setPositionRelative(slotLevelLabel, 9, offsetJa ? 1.5 : 0); slotLevelText.setOrigin(0, 0.25); slotInfoContainer.add([ this.slotName, slotLevelLabel, slotLevelText ]); @@ -1331,7 +1337,7 @@ class PartySlot extends Phaser.GameObjects.Container { this.slotHpOverlay.setVisible(false); this.slotHpText = addTextObject(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.setPositionRelative(this.slotHpBar, this.slotHpBar.width - 3, this.slotHpBar.height - 2 + (offsetJa ? 2 : 0)); this.slotHpText.setOrigin(1, 0); this.slotHpText.setVisible(false); From b33ffb29b36a5bfa9d003a95daba7406314745a2 Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Fri, 28 Feb 2025 14:08:55 +1100 Subject: [PATCH 03/21] [Bug] Fix mycelium might softlock (#5441) --- package-lock.json | 4 ++-- package.json | 2 +- src/data/ability.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e2c0d3a61b..b74d12ecd35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.2", + "version": "1.7.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.2", + "version": "1.7.3", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 418c22073c3..de543ce2bf2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.2", + "version": "1.7.3", "type": "module", "scripts": { "start": "vite", diff --git a/src/data/ability.ts b/src/data/ability.ts index 8c4b2ba380a..2b73fea60bc 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -5054,7 +5054,7 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr { const turnCommand = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; const isCommandFight = turnCommand?.command === Command.FIGHT; const move = turnCommand?.move?.move ? allMoves[turnCommand.move.move] : null; - if (this.condition(pokemon, move!) && isCommandFight) { + if (isCommandFight && this.condition(pokemon, move!)) { bypassSpeed.value = false; canCheckHeldItems.value = false; return false; From 13429446d35dd42377b16ec76825ff3b6effc6f1 Mon Sep 17 00:00:00 2001 From: AJ Fontaine <36677462+Fontbane@users.noreply.github.com> Date: Fri, 28 Feb 2025 01:18:58 -0500 Subject: [PATCH 04/21] [Bug] Fix tera slot wrapping (#5437) --- package-lock.json | 4 ++-- package.json | 2 +- src/data/trainer-config.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b74d12ecd35..c6dfdd7be04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.3", + "version": "1.7.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.3", + "version": "1.7.4", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index de543ce2bf2..19f64b56157 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.3", + "version": "1.7.4", "type": "module", "scripts": { "start": "vite", diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index a0158f28238..21b04c182e6 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -607,7 +607,7 @@ export class TrainerConfig { const shedinjaCanTera = !this.hasSpecialtyType() || this.specialtyType === Type.BUG; // Better to check one time than 6 const partyMemberIndexes = new Array(party.length).fill(null).map((_, i) => i) .filter(i => shedinjaCanTera || party[i].species.speciesId !== Species.SHEDINJA); // Shedinja can only Tera on Bug specialty type (or no specialty type) - const setPartySlot = !Utils.isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length - 1) : -1; // If we have a tera slot defined, wrap it to party size. + const setPartySlot = !Utils.isNullOrUndefined(slot) ? Phaser.Math.Wrap(slot, 0, party.length) : -1; // If we have a tera slot defined, wrap it to party size. for (let t = 0; t < Math.min(count(), party.length); t++) { const randomIndex = partyMemberIndexes.indexOf(setPartySlot) > -1 ? setPartySlot : Utils.randSeedItem(partyMemberIndexes); partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); From 942bcacb56a5e3d6364c408a124e09a16a6a4c23 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Fri, 28 Feb 2025 22:22:22 +0100 Subject: [PATCH 05/21] =?UTF-8?q?[Bug][Hotfix]=20Restrict=20Use=20Candies?= =?UTF-8?q?=20option=20in=20the=20Pok=C3=A9dex=20during=20Shop=20(#5446)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 2 +- src/ui/pokedex-page-ui-handler.ts | 11 +++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6dfdd7be04..d31469f4a45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.4", + "version": "1.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.4", + "version": "1.7.5", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 19f64b56157..1953b886c80 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.4", + "version": "1.7.5", "type": "module", "scripts": { "start": "vite", diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 99b25c3c383..49bb52dddbb 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -250,6 +250,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler { private availableVariants: number; private unlockedVariants: boolean[]; + private canUseCandies: boolean; + constructor() { super(Mode.POKEDEX_PAGE); } @@ -556,6 +558,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler { show(args: any[]): boolean { + // Allow the use of candies if we are in one of the whitelisted phases + this.canUseCandies = [ "TitlePhase", "SelectStarterPhase", "CommandPhase" ].includes(globalScene.getCurrentPhase()?.constructor.name ?? ""); + if (args.length >= 1 && args[0] === "refresh") { return false; } else { @@ -1626,7 +1631,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler { } break; case Button.STATS: - if (!isCaught || !isFormCaught) { + if (!isCaught || !isFormCaught || !this.canUseCandies) { error = true; } else { const ui = this.getUi(); @@ -1888,7 +1893,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler { if (this.isCaught()) { if (isFormCaught) { - this.updateButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.candyUpgradeIconElement, this.candyUpgradeLabel); + if (this.canUseCandies) { + this.updateButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.candyUpgradeIconElement, this.candyUpgradeLabel); + } if (this.canCycleShiny) { this.updateButtonIcon(SettingKeyboard.Button_Cycle_Shiny, gamepadType, this.shinyIconElement, this.shinyLabel); } From 118bdcc49ea317785c8e67e7e62ee94fcbf7807a Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 01:15:11 +0100 Subject: [PATCH 06/21] =?UTF-8?q?[Bug][UI/UX]=20Never=20select=20invisible?= =?UTF-8?q?=20containers=20in=20Pok=C3=A9dex=20(#5449)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/pokedex-ui-handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index a18f138e4f7..02c19f11813 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -986,7 +986,7 @@ export default class PokedexUiHandler extends MessageUiHandler { this.updateScroll(); const proportion = this.filterBarCursor / Math.max(1, this.filterBar.numFilters - 1); const targetCol = Math.min(8, proportion < 0.5 ? Math.floor(proportion * 8) : Math.ceil(proportion * 8)); - this.setCursor(Math.min(targetCol, numberOfStarters)); + this.setCursor(Math.min(targetCol, numberOfStarters - 1)); success = true; } break; @@ -1108,7 +1108,7 @@ export default class PokedexUiHandler extends MessageUiHandler { } break; case Button.DOWN: - if (currentRow < numOfRows - 1) { // not last row + if ((currentRow < numOfRows - 1) && (this.cursor + 9 < this.filteredPokemonData.length)) { // not last row if (currentRow - this.scrollCursor === 8) { // last row of visible pokemon this.scrollCursor++; this.updateScroll(); From 7cc5f40af8f0b37fc2e790f8d23c9310b0f72907 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 01:55:22 +0100 Subject: [PATCH 07/21] =?UTF-8?q?[Bug][UI/UX]=20Restore=20egg/tm=20move=20?= =?UTF-8?q?and=20passive=20icons=20when=20using=20filters=20in=20Pok=C3=A9?= =?UTF-8?q?dex=20(#5450)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/pokedex-ui-handler.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/ui/pokedex-ui-handler.ts b/src/ui/pokedex-ui-handler.ts index 02c19f11813..83739ba26a8 100644 --- a/src/ui/pokedex-ui-handler.ts +++ b/src/ui/pokedex-ui-handler.ts @@ -1577,6 +1577,37 @@ export default class PokedexUiHandler extends MessageUiHandler { container.icon.setTint(0); } + if (data.eggMove1) { + container.eggMove1Icon.setVisible(true); + } else { + container.eggMove1Icon.setVisible(false); + } + if (data.eggMove2) { + container.eggMove2Icon.setVisible(true); + } else { + container.eggMove2Icon.setVisible(false); + } + if (data.tmMove1) { + container.tmMove1Icon.setVisible(true); + } else { + container.tmMove1Icon.setVisible(false); + } + if (data.tmMove2) { + container.tmMove2Icon.setVisible(true); + } else { + container.tmMove2Icon.setVisible(false); + } + if (data.passive1) { + container.passive1Icon.setVisible(true); + } else { + container.passive1Icon.setVisible(false); + } + if (data.passive2) { + container.passive2Icon.setVisible(true); + } else { + container.passive2Icon.setVisible(false); + } + if (this.showDecorations) { if (this.pokerusSpecies.includes(data.species)) { From b348626ec2257352dc758e5aecaf4dcdd153fff7 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:00:56 +0100 Subject: [PATCH 08/21] [Bug][UI/UX] Make candy icons show up again in starter select screen (#5451) --- src/ui/abstact-option-select-ui-handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index 07e43a344dd..a462ed158cb 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -147,7 +147,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { itemIcon.setScale(3 * this.scale); this.optionSelectIcons.push(itemIcon); - this.optionSelectContainer.add(itemIcon); + this.optionSelectTextContainer.add(itemIcon); itemIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3)); @@ -156,7 +156,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { itemOverlayIcon.setScale(3 * this.scale); this.optionSelectIcons.push(itemOverlayIcon); - this.optionSelectContainer.add(itemOverlayIcon); + this.optionSelectTextContainer.add(itemOverlayIcon); itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3)); From d16197e950bbe59bf86976a5245a10a34c4c6af4 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 04:34:49 +0100 Subject: [PATCH 09/21] =?UTF-8?q?[Bug]=20Gendered=20forms=20display=20corr?= =?UTF-8?q?ect=20information=20in=20Pok=C3=A9dex=20(#5452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/pokedex-page-ui-handler.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 49bb52dddbb..e9060fb43b6 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -602,6 +602,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.battleForms = []; const species = this.species; + + let formKey = this.species?.forms.length > 0 ? this.species.forms[this.formIndex].formKey : ""; + this.isFormGender = formKey === "male" || formKey === "female"; + if (this.isFormGender && ((this.savedStarterAttributes.female === true && formKey === "male") || (this.savedStarterAttributes.female === false && formKey === "female"))) { + this.formIndex = (this.formIndex + 1) % 2; + formKey = this.species.forms[this.formIndex].formKey; + } + const formIndex = this.formIndex ?? 0; this.starterId = this.getStarterSpeciesId(this.species.speciesId); @@ -635,12 +643,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler { this.eggMoves = speciesEggMoves[this.starterId] ?? []; this.hasEggMoves = Array.from({ length: 4 }, (_, em) => (globalScene.gameData.starterData[this.starterId].eggMoves & (1 << em)) !== 0); - const formKey = this.species?.forms.length > 0 ? this.species.forms[this.formIndex].formKey : ""; this.tmMoves = speciesTmMoves[species.speciesId]?.filter(m => Array.isArray(m) ? (m[0] === formKey ? true : false ) : true) .map(m => Array.isArray(m) ? m[1] : m).sort((a, b) => allMoves[a].name > allMoves[b].name ? 1 : -1) ?? []; - this.isFormGender = formKey === "male" || formKey === "female"; - const passiveId = starterPassiveAbilities.hasOwnProperty(species.speciesId) ? species.speciesId : starterPassiveAbilities.hasOwnProperty(this.starterId) ? this.starterId : pokemonPrevolutions[this.starterId]; const passives = starterPassiveAbilities[passiveId]; From 89e8085c39c4f193124b731b5ea26b12734a367d Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 05:22:51 +0100 Subject: [PATCH 10/21] =?UTF-8?q?[Bug]=20Display=20Pok=C3=A9mon=20name=20i?= =?UTF-8?q?n=20Focus=20Punch=20lost=20focus=20message=20(#5448)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/move.ts | 2 +- test/moves/focus_punch.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 18f4b220911..11ce7069664 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -9384,7 +9384,7 @@ export function initMoves() { .attr(BypassBurnDamageReductionAttr), new AttackMove(Moves.FOCUS_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3) .attr(MessageHeaderAttr, (user, move) => i18next.t("moveTriggers:isTighteningFocus", { pokemonName: getPokemonNameWithAffix(user) })) - .attr(PreUseInterruptAttr, i18next.t("moveTriggers:lostFocus"), user => !!user.turnData.attacksReceived.find(r => r.damage)) + .attr(PreUseInterruptAttr, (user, target, move) => i18next.t("moveTriggers:lostFocus", { pokemonName: getPokemonNameWithAffix(user) }), user => !!user.turnData.attacksReceived.find(r => r.damage)) .punchingMove(), new AttackMove(Moves.SMELLING_SALTS, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 3) .attr(MovePowerMultiplierAttr, (user, target, move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1) diff --git a/test/moves/focus_punch.test.ts b/test/moves/focus_punch.test.ts index 9bf858dfda5..1f14a19fbd7 100644 --- a/test/moves/focus_punch.test.ts +++ b/test/moves/focus_punch.test.ts @@ -140,6 +140,6 @@ describe("Moves - Focus Punch", () => { await game.phaseInterceptor.to("MessagePhase", false); const consoleSpy = vi.spyOn(console, "log"); await game.phaseInterceptor.to("MoveEndPhase", true); - expect(consoleSpy).nthCalledWith(1, i18next.t("moveTriggers:lostFocus")); + expect(consoleSpy).nthCalledWith(1, i18next.t("moveTriggers:lostFocus", { pokemonName: "Charizard" })); }); }); From c7df847e661727c02bc0980337cd767f99dcb048 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 20:33:31 +0100 Subject: [PATCH 11/21] [Bug] Unlocking correct base form of Zygarde when captured (#5453) --- src/system/game-data.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 57e25325ba4..aefc583a98a 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1645,11 +1645,19 @@ export class GameData { } else if (formIndex === 3) { dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(1); } - } - const allFormChanges = pokemonFormChanges.hasOwnProperty(species.speciesId) ? pokemonFormChanges[species.speciesId] : []; - const toCurrentFormChanges = allFormChanges.filter(f => (f.formKey === formKey)); - if (toCurrentFormChanges.length > 0) { - dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0); + } else if (pokemon.species.speciesId === Species.ZYGARDE) { + if (formIndex === 4) { + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(2); + } else if (formIndex === 5) { + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(3); + } + } else { + const allFormChanges = pokemonFormChanges.hasOwnProperty(species.speciesId) ? pokemonFormChanges[species.speciesId] : []; + const toCurrentFormChanges = allFormChanges.filter(f => (f.formKey === formKey)); + if (toCurrentFormChanges.length > 0) { + // Needs to do this or Castform can unlock the wrong form, etc. + dexEntry.caughtAttr |= globalScene.gameData.getFormAttr(0); + } } } From 5c73a1ea46033d011ef2f1884a2b41e9cd88d31b Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:43:18 +0100 Subject: [PATCH 12/21] [Bug][UI/UX] Starter select screen now looks for and displays form-specific abilities (#5454) --- src/ui/starter-select-ui-handler.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 771554f18de..12dd668af39 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -8,6 +8,7 @@ import i18next from "i18next"; import type BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import { starterColors } from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; +import type { Ability } from "#app/data/ability"; import { allAbilities } from "#app/data/ability"; import { speciesEggMoves } from "#app/data/balance/egg-moves"; import { GrowthRate, getGrowthRateColor } from "#app/data/exp"; @@ -3364,7 +3365,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (dexEntry.caughtAttr) { - const ability = allAbilities[this.lastSpecies.getAbility(abilityIndex!)]; // TODO: is this bang correct? + let ability: Ability; + if (this.lastSpecies.forms?.length > 1) { + ability = allAbilities[this.lastSpecies.forms[formIndex ?? 0].getAbility(abilityIndex!)]; + } else { + ability = allAbilities[this.lastSpecies.getAbility(abilityIndex!)]; // TODO: is this bang correct? + } this.pokemonAbilityText.setText(ability.name); const isHidden = abilityIndex === (this.lastSpecies.ability2 ? 2 : 1); From 04ac5c376241b7026a244fff3faec429b1ade729 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:54:29 +0100 Subject: [PATCH 13/21] [Bug][UI/UX] Shiny button can cycle variants even if non-shiny form is uncaught (#5457) --- src/ui/pokedex-page-ui-handler.ts | 12 ++++++------ src/ui/starter-select-ui-handler.ts | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index e9060fb43b6..68df02c191d 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -1580,15 +1580,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler { starterAttributes.variant = newVariant; // store the selected variant this.savedStarterAttributes.variant = starterAttributes.variant; - if (newVariant > props.variant) { - this.setSpeciesDetails(this.species, { variant: newVariant as Variant }); - success = true; - } else { + if ((this.isCaught() & DexAttr.NON_SHINY) && (newVariant <= props.variant)) { this.setSpeciesDetails(this.species, { shiny: false, variant: 0 }); success = true; - starterAttributes.shiny = false; this.savedStarterAttributes.shiny = starterAttributes.shiny; + } else { + this.setSpeciesDetails(this.species, { variant: newVariant as Variant }); + success = true; } } } @@ -2201,7 +2200,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler { const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY); const isShinyCaught = !!(caughtAttr & DexAttr.SHINY); - this.canCycleShiny = isNonShinyCaught && isShinyCaught; + const caughtVariants = [ DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3 ].filter(v => caughtAttr & v); + this.canCycleShiny = (isNonShinyCaught && isShinyCaught) || (isShinyCaught && caughtVariants.length > 1); const isMaleCaught = !!(caughtAttr & DexAttr.MALE); const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 12dd668af39..543e24d3b97 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2068,20 +2068,20 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } while (newVariant !== props.variant); starterAttributes.variant = newVariant; // store the selected variant - // If going to a higher variant, display that - if (newVariant > props.variant) { + if ((this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY) && (newVariant <= props.variant)) { + // If we have run out of variants, go back to non shiny + this.setSpeciesDetails(this.lastSpecies, { shiny: false, variant: 0 }); + this.pokemonShinyIcon.setVisible(false); + success = true; + starterAttributes.shiny = false; + } else { + // If going to a higher variant, or only shiny forms are caught, go to next variant this.setSpeciesDetails(this.lastSpecies, { variant: newVariant as Variant }); // Cycle tint based on current sprite tint const tint = getVariantTint(newVariant as Variant); this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant as Variant)); this.pokemonShinyIcon.setTint(tint); success = true; - // If we have run out of variants, go back to non shiny - } else { - this.setSpeciesDetails(this.lastSpecies, { shiny: false, variant: 0 }); - this.pokemonShinyIcon.setVisible(false); - success = true; - starterAttributes.shiny = false; } } } @@ -3328,7 +3328,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isNonShinyCaught = !!(caughtAttr & DexAttr.NON_SHINY); const isShinyCaught = !!(caughtAttr & DexAttr.SHINY); - this.canCycleShiny = isNonShinyCaught && isShinyCaught; + const caughtVariants = [ DexAttr.DEFAULT_VARIANT, DexAttr.VARIANT_2, DexAttr.VARIANT_3 ].filter(v => caughtAttr & v); + this.canCycleShiny = (isNonShinyCaught && isShinyCaught) || (isShinyCaught && caughtVariants.length > 1); const isMaleCaught = !!(caughtAttr & DexAttr.MALE); const isFemaleCaught = !!(caughtAttr & DexAttr.FEMALE); From 8f280bec498568396662240231d487e64e61a9d4 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:11:05 +0100 Subject: [PATCH 14/21] [Bug][UI/UX] Restore V button in battle (#5459) --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 91367cf73ec..111464b5e5c 100644 --- a/index.html +++ b/index.html @@ -133,7 +133,7 @@ V -
+
V
From b50d2c07834c0cab0b39ab90ca489fc3636f6677 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:24:15 +0100 Subject: [PATCH 15/21] =?UTF-8?q?[Bug][UI/UX]=20Fix=20bug=20in=20Pok=C3=A9?= =?UTF-8?q?dex=20for=20Mothim=20and=20other=20niche=20cases=20(#5458)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/pokedex-page-ui-handler.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/pokedex-page-ui-handler.ts b/src/ui/pokedex-page-ui-handler.ts index 68df02c191d..eee900d411e 100644 --- a/src/ui/pokedex-page-ui-handler.ts +++ b/src/ui/pokedex-page-ui-handler.ts @@ -789,6 +789,10 @@ export default class PokedexPageUiHandler extends MessageUiHandler { const formIndex = otherFormIndex !== undefined ? otherFormIndex : this.formIndex; const caughtAttr = this.isCaught(species); + if (caughtAttr && (!species.forms.length || species.forms.length === 1)) { + return true; + } + const isFormCaught = (caughtAttr & globalScene.gameData.getFormAttr(formIndex ?? 0)) > 0n; return isFormCaught; } From 882b965da101c992e18752b22e77f203f8e9b9be Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sun, 2 Mar 2025 02:46:38 +0100 Subject: [PATCH 16/21] [Bug] Pledge moves in summary do not break the game (#5461) --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 11ce7069664..677ad9f0ebc 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5236,7 +5236,7 @@ export class CombinedPledgeTypeAttr extends VariableMoveTypeAttr { return false; } - const combinedPledgeMove = user.turnData.combiningPledge; + const combinedPledgeMove = user?.turnData?.combiningPledge; if (!combinedPledgeMove) { return false; } From 659bc82676ec23dd0193ce54ba459cff5c422084 Mon Sep 17 00:00:00 2001 From: damocleas Date: Sun, 2 Mar 2025 12:19:17 -0500 Subject: [PATCH 17/21] [i18n] Up version to 1.7.6, Update locales submodule --- package-lock.json | 4 ++-- package.json | 2 +- public/locales | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d31469f4a45..453a525581b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "1.7.5", + "version": "1.7.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "1.7.5", + "version": "1.7.6", "hasInstallScript": true, "dependencies": { "@material/material-color-utilities": "^0.2.7", diff --git a/package.json b/package.json index 1953b886c80..4c9204f60f9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pokemon-rogue-battle", "private": true, - "version": "1.7.5", + "version": "1.7.6", "type": "module", "scripts": { "start": "vite", diff --git a/public/locales b/public/locales index b4534f03ba8..0e5c6096ba2 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit b4534f03ba8eb8709486ee967257b6f3725702dd +Subproject commit 0e5c6096ba26f6b87aed1aab3fe9b0b23f6cbb7b From 73afb35c4d745d136287199225a04a6b8ea3db26 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:40:40 -0600 Subject: [PATCH 18/21] [GitHub] Update CODEOWNERS to fix team ownership (#5465) --- .github/CODEOWNERS | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8e7606f0a48..79ab1bdc38a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,19 @@ * @pagefaultgames/junior-dev-team # github actions/templates etc. - Dev Leads -/.github @pagefaultgames/dev-leads +/.github @pagefaultgames/senior-dev-team + +# Art Team +/public/**/*.png @pagefaultgames/art-team +/public/**/*.json @pagefaultgames/art-team +/public/images @pagefaultgames/art-team +/public/battle-anims @pagefaultgames/art-team + +# Audio files +*.mp3 @pagefaultgames/composer-team +*.wav @pagefaultgames/composer-team +*.ogg @pagefaultgames/composer-team +/public/audio @pagefaultgames/composer-team + +# Balance Files; contain actual code logic and must also be owned by dev team +/src/data/balance @pagefaultgames/balance-team @pagefaultgames/junior-dev-team \ No newline at end of file From 6f686a05e39cb75c2ee110ab996b2b4ed0735cb0 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Sun, 2 Mar 2025 20:35:59 +0100 Subject: [PATCH 19/21] [UI/UX] [Bug] Hiding tera button when toggling on stats mode (#5466) --- src/ui/starter-select-ui-handler.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 543e24d3b97..34a29411de4 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -3353,7 +3353,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey)) .map((_, f) => dexEntry.caughtAttr & globalScene.gameData.getFormAttr(f)).filter(f => f).length > 1; this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1; - this.canCycleTera = globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2); + this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2); } if (dexEntry.caughtAttr && species.malePercent !== null) { @@ -3858,12 +3858,20 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.showStats(); this.statsMode = true; this.pokemonSprite.setVisible(false); + this.teraIcon.setVisible(false); + this.canCycleTera = false; + this.updateInstructions(); } else { this.statsMode = false; this.statsContainer.setVisible(false); this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr); //@ts-ignore this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!? + this.teraIcon.setVisible(globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id)); + const props = globalScene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)); + const formIndex = props.formIndex; + this.canCycleTera = !this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(this.lastSpecies.speciesId, formIndex ?? 0).type2); + this.updateInstructions(); } } From 5e469620ef8ed098d22c79d279ecdfdbaed0ba22 Mon Sep 17 00:00:00 2001 From: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com> Date: Sun, 2 Mar 2025 19:15:51 -0600 Subject: [PATCH 20/21] [Bug] Fix battle-anims crashing in certain cases (#5337) --- src/data/battle-anims.ts | 132 +++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index a179f3a3e9b..a42779563f2 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -1,7 +1,20 @@ import { globalScene } from "#app/global-scene"; -import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move"; +import { + AttackMove, + BeakBlastHeaderAttr, + DelayedAttackAttr, + MoveFlags, + SelfStatusMove, + allMoves, +} from "./move"; import type Pokemon from "../field/pokemon"; -import * as Utils from "../utils"; +import { + type nil, + getFrameMs, + getEnumKeys, + getEnumValues, + animationFileName, +} from "../utils"; import type { BattlerIndex } from "../battle"; import type { Element } from "json-stable-stringify"; import { Moves } from "#enums/moves"; @@ -401,7 +414,7 @@ class AnimTimedUpdateBgEvent extends AnimTimedBgEvent { if (Object.keys(tweenProps).length) { globalScene.tweens.add(Object.assign({ targets: moveAnim.bgSprite, - duration: Utils.getFrameMs(this.duration * 3) + duration: getFrameMs(this.duration * 3) }, tweenProps)); } return this.duration * 2; @@ -437,7 +450,7 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent { globalScene.tweens.add({ targets: moveAnim.bgSprite, - duration: Utils.getFrameMs(this.duration * 3) + duration: getFrameMs(this.duration * 3) }); return this.duration * 2; @@ -455,8 +468,8 @@ export const encounterAnims = new Map(); export function initCommonAnims(): Promise { return new Promise(resolve => { - const commonAnimNames = Utils.getEnumKeys(CommonAnim); - const commonAnimIds = Utils.getEnumValues(CommonAnim); + const commonAnimNames = getEnumKeys(CommonAnim); + const commonAnimIds = getEnumValues(CommonAnim); const commonAnimFetches: Promise>[] = []; for (let ca = 0; ca < commonAnimIds.length; ca++) { const commonAnimId = commonAnimIds[ca]; @@ -493,7 +506,7 @@ export function initMoveAnim(move: Moves): Promise { const defaultMoveAnim = allMoves[move] instanceof AttackMove ? Moves.TACKLE : allMoves[move] instanceof SelfStatusMove ? Moves.FOCUS_ENERGY : Moves.TAIL_WHIP; const fetchAnimAndResolve = (move: Moves) => { - globalScene.cachedFetch(`./battle-anims/${Utils.animationFileName(move)}.json`) + globalScene.cachedFetch(`./battle-anims/${animationFileName(move)}.json`) .then(response => { const contentType = response.headers.get("content-type"); if (!response.ok || contentType?.indexOf("application/json") === -1) { @@ -550,7 +563,7 @@ function useDefaultAnim(move: Moves, defaultMoveAnim: Moves) { * @remarks use {@linkcode useDefaultAnim} to use a default animation */ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) { - const moveName = Utils.animationFileName(move); + const moveName = animationFileName(move); console.warn(`Could not load animation file for move '${moveName}'`, ...optionalParams); } @@ -560,7 +573,7 @@ function logMissingMoveAnim(move: Moves, ...optionalParams: any[]) { */ export async function initEncounterAnims(encounterAnim: EncounterAnim | EncounterAnim[]): Promise { const anims = Array.isArray(encounterAnim) ? encounterAnim : [ encounterAnim ]; - const encounterAnimNames = Utils.getEnumKeys(EncounterAnim); + const encounterAnimNames = getEnumKeys(EncounterAnim); const encounterAnimFetches: Promise>[] = []; for (const anim of anims) { if (encounterAnims.has(anim) && !isNullOrUndefined(encounterAnims.get(anim))) { @@ -922,7 +935,7 @@ export abstract class BattleAnim { let f = 0; globalScene.tweens.addCounter({ - duration: Utils.getFrameMs(3), + duration: getFrameMs(3), repeat: anim?.frames.length ?? 0, onRepeat: () => { if (!f) { @@ -994,47 +1007,39 @@ export abstract class BattleAnim { const moveSprite = sprites[graphicIndex]; if (spritePriorities[graphicIndex] !== frame.priority) { spritePriorities[graphicIndex] = frame.priority; + /** Move the position that the moveSprite is rendered in based on the priority. + * @param priority The priority level to draw the sprite. + * - 0: Draw the sprite in front of the pokemon on the field. + * - 1: Draw the sprite in front of the user pokemon. + * - 2: Draw the sprite in front of its `bgSprite` (if it has one), or its + * `AnimFocus` (if that is user/target), otherwise behind everything. + * - 3: Draw the sprite behind its `AnimFocus` (if that is user/target), otherwise in front of everything. + */ const setSpritePriority = (priority: number) => { - switch (priority) { - case 0: - globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, globalScene.getEnemyPokemon(false) ?? globalScene.getPlayerPokemon(false)!); // TODO: is this bang correct? - break; - case 1: - globalScene.field.moveTo(moveSprite, globalScene.field.getAll().length - 1); - break; - case 2: - switch (frame.focus) { - case AnimFocus.USER: - if (this.bgSprite) { - globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite); - } else { - globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct? - } - break; - case AnimFocus.TARGET: - globalScene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct? - break; - default: - setSpritePriority(1); - break; - } - break; - case 3: - switch (frame.focus) { - case AnimFocus.USER: - globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct? - break; - case AnimFocus.TARGET: - globalScene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct? - break; - default: - setSpritePriority(1); - break; - } - break; - default: - setSpritePriority(1); + /** The sprite we are moving the moveSprite in relation to */ + let targetSprite: Phaser.GameObjects.GameObject | nil; + /** The method that is being used to move the sprite.*/ + let moveFunc: ((sprite: Phaser.GameObjects.GameObject, target: Phaser.GameObjects.GameObject) => void) | + ((sprite: Phaser.GameObjects.GameObject) => void) = globalScene.field.bringToTop; + + if (priority === 0) { // Place the sprite in front of the pokemon on the field. + targetSprite = globalScene.getEnemyField().find(p => p) ?? globalScene.getPlayerField().find(p => p); + console.log(typeof targetSprite); + moveFunc = globalScene.field.moveBelow; + } else if (priority === 2 && this.bgSprite) { + moveFunc = globalScene.field.moveAbove; + targetSprite = this.bgSprite; + } else if (priority === 2 || priority === 3) { + moveFunc = priority === 2 ? globalScene.field.moveBelow : globalScene.field.moveAbove; + if (frame.focus === AnimFocus.USER) { + targetSprite = this.user; + } else if (frame.focus === AnimFocus.TARGET) { + targetSprite = this.target; + } } + // If target sprite is not undefined and exists in the field container, then move the sprite using the moveFunc. + // Otherwise, default to just bringing it to the top. + targetSprite && globalScene.field.exists(targetSprite) ? moveFunc.bind(globalScene.field)(moveSprite as Phaser.GameObjects.GameObject, targetSprite) : globalScene.field.bringToTop(moveSprite as Phaser.GameObjects.GameObject); }; setSpritePriority(frame.priority); } @@ -1052,11 +1057,13 @@ export abstract class BattleAnim { } } if (anim?.frameTimedEvents.has(f)) { - for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct? - r = Math.max((anim.frames.length - f) + event.execute(this), r); + const base = anim.frames.length - f; + // Bang is correct due to `has` check above, which cannot return true for an undefined / null `f` + for (const event of anim.frameTimedEvents.get(f)!) { + r = Math.max(base + event.execute(this), r); } } - const targets = Utils.getEnumValues(AnimFrameTarget); + const targets = getEnumValues(AnimFrameTarget); for (const i of targets) { const count = i === AnimFrameTarget.GRAPHIC ? g : i === AnimFrameTarget.USER ? u : t; if (count < spriteCache[i].length) { @@ -1084,7 +1091,7 @@ export abstract class BattleAnim { } if (r) { globalScene.tweens.addCounter({ - duration: Utils.getFrameMs(r), + duration: getFrameMs(r), onComplete: () => cleanUpAndComplete() }); } else { @@ -1166,7 +1173,7 @@ export abstract class BattleAnim { let existingFieldSprites = globalScene.field.getAll().slice(0); globalScene.tweens.addCounter({ - duration: Utils.getFrameMs(3) * frameTimeMult, + duration: getFrameMs(3) * frameTimeMult, repeat: anim!.frames.length, onRepeat: () => { existingFieldSprites = globalScene.field.getAll().slice(0); @@ -1215,11 +1222,12 @@ export abstract class BattleAnim { } } if (anim?.frameTimedEvents.get(frameCount)) { + const base = anim.frames.length - frameCount; for (const event of anim.frameTimedEvents.get(frameCount)!) { - totalFrames = Math.max((anim.frames.length - frameCount) + event.execute(this, frameTimedEventPriority), totalFrames); + totalFrames = Math.max(base + event.execute(this, frameTimedEventPriority), totalFrames); } } - const targets = Utils.getEnumValues(AnimFrameTarget); + const targets = getEnumValues(AnimFrameTarget); for (const i of targets) { const count = graphicFrameCount; if (count < spriteCache[i].length) { @@ -1244,7 +1252,7 @@ export abstract class BattleAnim { } if (totalFrames) { globalScene.tweens.addCounter({ - duration: Utils.getFrameMs(totalFrames), + duration: getFrameMs(totalFrames), onComplete: () => cleanUpAndComplete() }); } else { @@ -1342,15 +1350,15 @@ export class EncounterBattleAnim extends BattleAnim { } export async function populateAnims() { - const commonAnimNames = Utils.getEnumKeys(CommonAnim).map(k => k.toLowerCase()); + const commonAnimNames = getEnumKeys(CommonAnim).map(k => k.toLowerCase()); const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, "")); - const commonAnimIds = Utils.getEnumValues(CommonAnim) as CommonAnim[]; - const chargeAnimNames = Utils.getEnumKeys(ChargeAnim).map(k => k.toLowerCase()); + const commonAnimIds = getEnumValues(CommonAnim) as CommonAnim[]; + const chargeAnimNames = getEnumKeys(ChargeAnim).map(k => k.toLowerCase()); const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, " ")); - const chargeAnimIds = Utils.getEnumValues(ChargeAnim) as ChargeAnim[]; + const chargeAnimIds = getEnumValues(ChargeAnim) as ChargeAnim[]; const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/; const moveNameToId = {}; - for (const move of Utils.getEnumValues(Moves).slice(1)) { + for (const move of getEnumValues(Moves).slice(1)) { const moveName = Moves[move].toUpperCase().replace(/\_/g, ""); moveNameToId[moveName] = move; } From cabcfcbd39968c01cb03e4e76288a716926687b1 Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Mon, 3 Mar 2025 13:22:37 +1100 Subject: [PATCH 21/21] [Balance] Make megas/max player pokemon unable to tera (#5469) Co-authored-by: damocleas --- src/field/pokemon.ts | 14 ++++++++++++-- src/ui/command-ui-handler.ts | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f0486a8f111..53d4b6c54d2 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1226,10 +1226,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Checks if the {@linkcode Pokemon} has is the specified {@linkcode Species} or is fused with it. * @param species the pokemon {@linkcode Species} to check + * @param formKey If provided, requires the species to be in that form * @returns `true` if the pokemon is the species or is fused with it, `false` otherwise */ - hasSpecies(species: Species): boolean { - return this.species.speciesId === species || this.fusionSpecies?.speciesId === species; + hasSpecies(species: Species, formKey?: string): boolean { + if (Utils.isNullOrUndefined(formKey)) { + return this.species.speciesId === species || this.fusionSpecies?.speciesId === species; + } + + return (this.species.speciesId === species && this.getFormKey() === formKey) || (this.fusionSpecies?.speciesId === species && this.getFusionFormKey() === formKey); } abstract isBoss(): boolean; @@ -3204,6 +3209,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!)); } + isMega(): boolean { + const megaForms = [ SpeciesFormKey.MEGA, SpeciesFormKey.MEGA_X, SpeciesFormKey.MEGA_Y, SpeciesFormKey.PRIMAL ] as string[]; + return megaForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && megaForms.includes(this.getFusionFormKey()!)); + } + canAddTag(tagType: BattlerTagType): boolean { if (this.getTag(tagType)) { return false; diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index f23cc78c9f7..20cffbbe30a 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -10,6 +10,7 @@ import { globalScene } from "#app/global-scene"; import { TerastallizeAccessModifier } from "#app/modifier/modifier"; import { Type } from "#app/enums/type"; import { getTypeRgb } from "#app/data/type"; +import { Species } from "#enums/species"; export enum Command { FIGHT = 0, @@ -180,9 +181,11 @@ export default class CommandUiHandler extends UiHandler { canTera(): boolean { const hasTeraMod = !!globalScene.getModifiers(TerastallizeAccessModifier).length; + const activePokemon = globalScene.getField()[this.fieldIndex]; + const isBlockedForm = activePokemon.isMega() || activePokemon.isMax() || activePokemon.hasSpecies(Species.NECROZMA, "ultra"); const currentTeras = globalScene.arena.playerTerasUsed; const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 ? 1 : 0; - return hasTeraMod && (currentTeras + plannedTera) < 1; + return hasTeraMod && !isBlockedForm && (currentTeras + plannedTera) < 1; } toggleTeraButton() {