Compare commits

...

15 Commits

Author SHA1 Message Date
Frederico Santos
d61c8f2870
Merge pull request #3613 from pagefaultgames/main
Merge main into beta
2024-08-18 06:50:45 +01:00
NightKev
0e6c2952ca
Make Disguise properly reset form on arena reset when fainted (#3612) 2024-08-18 05:05:04 +01:00
Mumble
192aa63635
[Bug][Hotfix] Final Boss MBH no longer transferrable (#3611)
* Should fix it.

* typedocs fixes

---------

Co-authored-by: Frutescens <info@laptop>
2024-08-18 04:28:06 +01:00
cam
abced6cf02
[Sprite] Lumineon female spritesheet fix (#3608)
fix from Vari
2024-08-18 04:17:21 +01:00
cam
5f6cb6ce00
[Sprite] Floette animation fix - Xatu female variant fix (#3610)
* 177-178 icons, variant icons

* 178 icons

* [HotFix][Sprite] Xatu female variants added

* [HotFix][Sprite] Floette json: update to match images

* Xatu variant- reverted _masterlist

reverted _masterlist.json
added anim files for both female variants

* [fix] Xatu female: show variants, added back sprite anim

Edited _masterlist on correct keys
added anim json for back sprites
2024-08-18 04:14:25 +01:00
AJ Fontaine
0e92366cac
Fixed egg moves being relearnable in daily runs (#3604) 2024-08-18 02:23:02 +01:00
innerthunder
8704723c9c
Fix missing form change logic for Cramorant (#3603) 2024-08-18 02:22:21 +01:00
Mumble
5ede6a54c6
[Hotfix] End Biome Catch Problems (#3605)
* Needs more testing.

* removed debugging

---------

Co-authored-by: Frutescens <info@laptop>
2024-08-18 01:09:28 +01:00
innerthunder
2b853bae25
[Hotfix] Fix Pokemon info not fully appearing after switch-out (#3596)
* Add hideInfo param to leaveField

* Update docs for leaveField
2024-08-17 23:25:03 +01:00
Leo Kim
b59cb128bf
fix female bug. refine variable name also (#3601) 2024-08-17 22:01:35 +01:00
Mumble
616219d17e
[Hotfix] Removed isFreshStartChallenge() check (#3599)
* Removed isFreshStartChallenge() check

* Better conditional

---------

Co-authored-by: Frutescens <info@laptop>
2024-08-18 05:50:50 +10:00
damocleas
e192e57c63
[Balance] Balance Hotfixes for August 17 Update (#3594)
* [Balance] Balance Hotfixes for August 17 Update

* Eternatus Moveset fix

* fixed Cresselia passive

* fixed Jirachi Egg Moves

* fixed Doduo and Arctozolt egg moves
2024-08-17 20:48:16 +01:00
Leo Kim
15584f8f1e
fix typecast to BigInt (#3598) 2024-08-17 20:47:45 +01:00
Leo Kim
54460405b1
[Hotfix] Fixed the bug where Pokémon with only rare/epic shiny but no common shiny were unable to use cycle shiny (#3593)
* Fixed the bug where Pokémon with only rare/epic shiny but no common shiny were unable to use cycle shiny

* remove unecessary log

* fix condition
2024-08-17 19:36:25 +01:00
Frederico Santos
451a1a2c50
Merge pull request #3540 from pagefaultgames/beta
Beta #2
2024-08-17 17:59:59 +01:00
47 changed files with 30382 additions and 2831 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2513,7 +2513,6 @@
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:edb2df3a947401efb05329a2c96d5d73:f256d83ef4df17c17958acc6e0432ab0:bad05b37c157676604256a043511a6a2$"
"version": "3.0"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -3815,6 +3815,11 @@
1,
1
],
"178": [
0,
2,
2
],
"185": [
0,
1,
@ -7833,6 +7838,11 @@
1,
1
],
"178": [
0,
2,
2
],
"185": [
0,
1,

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -5,7 +5,7 @@ import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
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, TurnHeldItemTransferModifier, 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";
@ -37,7 +37,7 @@ import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import { addUiThemeOverrides } from "./ui/ui-theme";
import PokemonData from "./system/pokemon-data";
import { Nature } from "./data/nature";
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem } from "./data/pokemon-forms";
import { SpeciesFormChangeManualTrigger, SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTrigger, pokemonFormChanges, FormChangeItem, SpeciesFormChange } from "./data/pokemon-forms";
import { FormChangePhase, QuietFormChangePhase } from "./form-change-phase";
import { getTypeRgb } from "./data/type";
import PokemonSpriteSparkleHandler from "./field/pokemon-sprite-sparkle-handler";
@ -2579,7 +2579,7 @@ export default class BattleScene extends SceneBase {
// in case this is NECROZMA, determine which forms this
const matchingFormChangeOpts = pokemonFormChanges[pokemon.species.speciesId].filter(fc => fc.findTrigger(formChangeTriggerType) && fc.canChange(pokemon));
let matchingFormChange;
let matchingFormChange: SpeciesFormChange | null;
if (pokemon.species.speciesId === Species.NECROZMA && matchingFormChangeOpts.length > 1) {
// Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves.
const formChangeItemModifiers = (this.findModifiers(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id) as PokemonFormChangeItemModifier[]).filter(m => m.active).map(m => m.formChangeItem);
@ -2666,7 +2666,9 @@ export default class BattleScene extends SceneBase {
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
this.fadeOutBgm(Utils.fixedInt(2000), false);
this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, undefined, () => {
this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true);
const finalBossMBH = getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as TurnHeldItemTransferModifier;
finalBossMBH.setTransferrableFalse();
this.addEnemyModifier(finalBossMBH, false, true);
pokemon.generateAndPopulateMoveset(1);
this.setFieldScale(0.75);
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);

View File

@ -5039,6 +5039,7 @@ export function initAbilities() {
(pokemon, abilityName) => i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }),
(pokemon) => Math.floor(pokemon.getMaxHp() / 8))
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.bypassFaint()
.ignorable(),
new Ability(Abilities.BATTLE_BOND, 7)
.attr(PostVictoryFormChangeAbAttr, () => 2)
@ -5191,6 +5192,7 @@ export function initAbilities() {
.attr(FormBlockDamageAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0, BattlerTagType.ICE_FACE,
(pokemon, abilityName) => i18next.t("abilityTriggers:iceFaceAvoidedDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName: abilityName }))
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.bypassFaint()
.ignorable(),
new Ability(Abilities.POWER_SPOT, 8)
.attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3),

View File

@ -37,7 +37,7 @@ export const speciesEggMoves = {
[Species.SLOWPOKE]: [ Moves.BOUNCY_BUBBLE, Moves.FLAMETHROWER, Moves.MYSTICAL_POWER, Moves.SHED_TAIL ],
[Species.MAGNEMITE]: [ Moves.PARABOLIC_CHARGE, Moves.BODY_PRESS, Moves.ICE_BEAM, Moves.THUNDERCLAP ],
[Species.FARFETCHD]: [ Moves.IVY_CUDGEL, Moves.TRIPLE_ARROWS, Moves.ROOST, Moves.VICTORY_DANCE ],
[Species.DODUO]: [ Moves.ICE_SPINNER, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.DODUO]: [ Moves.TRIPLE_AXEL, Moves.MULTI_ATTACK, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS ],
[Species.SEEL]: [ Moves.FREEZE_DRY, Moves.BOUNCY_BUBBLE, Moves.SLACK_OFF, Moves.STEAM_ERUPTION ],
[Species.GRIMER]: [ Moves.SUCKER_PUNCH, Moves.CURSE, Moves.STRENGTH_SAP, Moves.NOXIOUS_TORQUE ],
[Species.SHELLDER]: [ Moves.ROCK_BLAST, Moves.WATER_SHURIKEN, Moves.BANEFUL_BUNKER, Moves.BONE_RUSH ],
@ -198,7 +198,7 @@ export const speciesEggMoves = {
[Species.KYOGRE]: [ Moves.BOUNCY_BUBBLE, Moves.HURRICANE, Moves.FREEZE_DRY, Moves.ELECTRO_SHOT ],
[Species.GROUDON]: [ Moves.STONE_AXE, Moves.SOLAR_BLADE, Moves.MORNING_SUN, Moves.SACRED_FIRE ],
[Species.RAYQUAZA]: [ Moves.V_CREATE, Moves.DRAGON_DARTS, Moves.CORE_ENFORCER, Moves.OBLIVION_WING ],
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.FLOATY_FALL, Moves.TRIPLE_ARROWS, Moves.SHELL_SMASH ],
[Species.JIRACHI]: [ Moves.TACHYON_CUTTER, Moves.TRIPLE_ARROWS, Moves.ROCK_SLIDE, Moves.SHELL_SMASH ],
[Species.DEOXYS]: [ Moves.COLLISION_COURSE, Moves.EARTH_POWER, Moves.PARTING_SHOT, Moves.LUMINA_CRASH ],
[Species.TURTWIG]: [ Moves.SHELL_SMASH, Moves.MIGHTY_CLEAVE, Moves.ICE_SPINNER, Moves.SAPPY_SEED ],
[Species.CHIMCHAR]: [ Moves.FIERY_DANCE, Moves.SECRET_SWORD, Moves.TRIPLE_AXEL, Moves.SACRED_FIRE ],
@ -418,7 +418,7 @@ export const speciesEggMoves = {
[Species.CELESTEELA]: [ Moves.RECOVER, Moves.BUZZY_BUZZ, Moves.SANDSEAR_STORM, Moves.OBLIVION_WING ],
[Species.KARTANA]: [ Moves.MIGHTY_CLEAVE, Moves.PSYBLADE, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.GUZZLORD]: [ Moves.SUCKER_PUNCH, Moves.COMEUPPANCE, Moves.SLACK_OFF, Moves.SHED_TAIL ],
[Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.CLANGOROUS_SOUL ],
[Species.NECROZMA]: [ Moves.CLANGOROUS_SOUL, Moves.SACRED_FIRE, Moves.ASTRAL_BARRAGE, Moves.DYNAMAX_CANNON ],
[Species.MAGEARNA]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.MOONBLAST, Moves.MAKE_IT_RAIN ],
[Species.MARSHADOW]: [ Moves.POWER_UP_PUNCH, Moves.TRIPLE_AXEL, Moves.METEOR_MASH, Moves.STORM_THROW ],
[Species.POIPOLE]: [ Moves.CORE_ENFORCER, Moves.ICE_BEAM, Moves.SEARING_SHOT, Moves.MALIGNANT_CHAIN ],
@ -458,7 +458,7 @@ export const speciesEggMoves = {
[Species.MORPEKO]: [ Moves.TRIPLE_AXEL, Moves.OBSTRUCT, Moves.SWORDS_DANCE, Moves.COLLISION_COURSE ],
[Species.CUFANT]: [ Moves.LIQUIDATION, Moves.CURSE, Moves.COMBAT_TORQUE, Moves.GIGATON_HAMMER ],
[Species.DRACOZOLT]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.FIRE_LASH, Moves.DRAGON_DANCE ],
[Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.ARCTOZOLT]: [ Moves.MOUNTAIN_GALE, Moves.AQUA_STEP, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.DRACOVISH]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.THUNDER_FANG, Moves.DRAGON_DANCE ],
[Species.ARCTOVISH]: [ Moves.ICE_FANG, Moves.THUNDER_FANG, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ],
[Species.DURALUDON]: [ Moves.CORE_ENFORCER, Moves.BODY_PRESS, Moves.RECOVER, Moves.TACHYON_CUTTER ],

View File

@ -837,6 +837,8 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.CRAMORANT, "", "gorging", new SpeciesFormChangeManualTrigger, true, new SpeciesFormChangeCondition(p => p.getHpRatio() < .5)),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeManualTrigger, true),
new SpeciesFormChange(Species.CRAMORANT, "gulping", "", new SpeciesFormChangeActiveTrigger(false), true),
new SpeciesFormChange(Species.CRAMORANT, "gorging", "", new SpeciesFormChangeActiveTrigger(false), true),
]
};

View File

@ -3559,7 +3559,7 @@ export const starterPassiveAbilities = {
[Species.HEATRAN]: Abilities.EARTH_EATER,
[Species.REGIGIGAS]: Abilities.MINDS_EYE,
[Species.GIRATINA]: Abilities.SHADOW_SHIELD,
[Species.CRESSELIA]: Abilities.MAGIC_BOUNCE,
[Species.CRESSELIA]: Abilities.UNAWARE,
[Species.PHIONE]: Abilities.SIMPLE,
[Species.MANAPHY]: Abilities.PRIMORDIAL_SEA,
[Species.DARKRAI]: Abilities.UNNERVE,

View File

@ -922,7 +922,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
*/
getLearnableLevelMoves(): Moves[] {
let levelMoves = this.getLevelMoves(1, true).map(lm => lm[1]);
if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge()) {
if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) {
levelMoves = this.getUnlockedEggMoves().concat(levelMoves);
}
return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm));
@ -3223,14 +3223,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* Causes a Pokemon to leave the field (such as in preparation for a switch out/escape).
* @param clearEffects Indicates if effects should be cleared (true) or passed
* to the next pokemon, such as during a baton pass (false)
* @param hideInfo Indicates if this should also play the animation to hide the Pokemon's
* info container.
*/
leaveField(clearEffects: boolean = true) {
leaveField(clearEffects: boolean = true, hideInfo: boolean = true) {
this.resetTurnData();
if (clearEffects) {
this.resetSummonData();
this.resetBattleData();
}
if (hideInfo) {
this.hideInfo();
}
this.setVisible(false);
this.scene.field.remove(this);
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeActiveTrigger, true);
@ -3780,7 +3784,7 @@ export class EnemyPokemon extends Pokemon {
this.moveset = (formIndex !== undefined ? formIndex : this.formIndex)
? [
new PokemonMove(Moves.DYNAMAX_CANNON),
new PokemonMove(Moves.CROSS_POISON),
new PokemonMove(Moves.SLUDGE_BOMB),
new PokemonMove(Moves.FLAMETHROWER),
new PokemonMove(Moves.RECOVER, 0, -4)
]

View File

@ -62,7 +62,7 @@ export class GameMode implements GameModeConfig {
* @returns true if the game mode has that challenge
*/
hasChallenge(challenge: Challenges): boolean {
return this.challenges.some(c => c.id === challenge);
return this.challenges.some(c => c.id === challenge && c.value !== 0);
}
/**

View File

@ -2338,7 +2338,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
* @see {@linkcode modifierTypes[MINI_BLACK_HOLE]}
*/
export class TurnHeldItemTransferModifier extends HeldItemTransferModifier {
readonly isTransferrable: boolean = true;
isTransferrable: boolean = true;
constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
}
@ -2362,6 +2362,10 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier {
getMaxHeldItemCount(pokemon: Pokemon): integer {
return 1;
}
setTransferrableFalse(): void {
this.isTransferrable = false;
}
}
/**

View File

@ -1635,7 +1635,7 @@ export class SwitchSummonPhase extends SummonPhase {
})
);
this.scene.playSound("pb_rel");
pokemon.hideInfo(); // this is also done by pokemon.leaveField(), but needs to go earlier for animation purposes
pokemon.hideInfo();
pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, "Sine.easeIn");
this.scene.tweens.add({
targets: pokemon,
@ -1643,9 +1643,7 @@ export class SwitchSummonPhase extends SummonPhase {
ease: "Sine.easeIn",
scale: 0.5,
onComplete: () => {
// 300ms delay on leaveField is necessary to avoid calling hideInfo() twice
// and double-animating the stats panel slideout
this.scene.time.delayedCall(300, () => pokemon.leaveField(!this.batonPass));
pokemon.leaveField(!this.batonPass, false);
this.scene.time.delayedCall(750, () => this.switchAndSummon());
}
});
@ -2036,7 +2034,8 @@ export class CommandPhase extends FieldPhase {
}
break;
case Command.BALL:
if (!this.scene.gameMode.isFreshStartChallenge() && this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1))) {
const notInDex = (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1);
if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || this.scene.gameMode.isFreshStartChallenge() || notInDex )) {
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => {

View File

@ -1709,7 +1709,7 @@ export class GameData {
}
getFormAttr(formIndex: integer): bigint {
return BigInt(1 << (7 + formIndex));
return BigInt(1) << BigInt(7 + formIndex);
}
consolidateDexData(dexData: DexData): void {

View File

@ -2,12 +2,12 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
import GameManager from "#test/utils/gameManager";
import { getMovePosition } from "#test/utils/gameManagerUtils";
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 { CommandPhase, MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase } from "#app/phases.js";
import { BattleStat } from "#app/data/battle-stat.js";
import { SPLASH_ONLY } from "../utils/testUtils";
import { Mode } from "#app/ui/ui.js";
const TIMEOUT = 20 * 1000;
@ -38,7 +38,7 @@ describe("Abilities - Disguise", () => {
game.override.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]);
}, TIMEOUT);
it("takes no damage from attacking move and transforms to Busted form, taking 1/8 max HP damage from the disguise breaking", async () => {
it("takes no damage from attacking move and transforms to Busted form, takes 1/8 max HP damage from the disguise breaking", async () => {
await game.startBattle();
const mimikyu = game.scene.getEnemyPokemon()!;
@ -134,17 +134,30 @@ describe("Abilities - Disguise", () => {
expect(mimikyu.formIndex).toBe(bustedForm);
}, TIMEOUT);
it("reverts to Disguised on arena reset", async () => {
game.override.startingWave(4);
it("persists form change when wave changes with no arena reset", async () => {
game.override.starterSpecies(0);
game.override.starterForms({
[Species.MIMIKYU]: bustedForm
});
await game.startBattle([Species.FURRET, Species.MIMIKYU]);
const mimikyu = game.scene.getParty()[1]!;
expect(mimikyu.formIndex).toBe(bustedForm);
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents();
await game.toNextWave();
expect(mimikyu.formIndex).toBe(bustedForm);
}, TIMEOUT);
it("reverts to Disguised form on arena reset", async () => {
game.override.startingWave(4);
game.override.starterSpecies(Species.MIMIKYU);
game.override.starterForms({
[Species.MIMIKYU]: bustedForm
});
game.override.enemySpecies(Species.MAGIKARP);
game.override.enemyAbility(Abilities.BALL_FETCH);
await game.startBattle();
const mimikyu = game.scene.getPlayerPokemon()!;
@ -153,10 +166,41 @@ describe("Abilities - Disguise", () => {
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents();
await game.phaseInterceptor.to(TurnEndPhase);
game.doSelectModifier();
await game.phaseInterceptor.to(TurnInitPhase);
await game.toNextWave();
expect(mimikyu.formIndex).toBe(disguisedForm);
}, TIMEOUT);
it("reverts to Disguised form on biome change when fainted", async () => {
game.override.startingWave(10);
game.override.starterSpecies(0);
game.override.starterForms({
[Species.MIMIKYU]: bustedForm
});
await game.startBattle([Species.MIMIKYU, Species.FURRET]);
const mimikyu1 = game.scene.getPlayerPokemon()!;
expect(mimikyu1.formIndex).toBe(bustedForm);
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.killPokemon(mimikyu1);
game.doSelectPartyPokemon(1);
await game.toNextTurn();
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
await game.doKillOpponents();
game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { // TODO: Make tests run in set mode instead of switch mode
game.setMode(Mode.MESSAGE);
game.endPhase();
}, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase));
game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
game.setMode(Mode.MESSAGE);
game.endPhase();
}, () => game.isCurrentPhase(CommandPhase) || game.isCurrentPhase(TurnInitPhase));
await game.phaseInterceptor.to("PartyHealPhase");
expect(mimikyu1.formIndex).toBe(disguisedForm);
}, TIMEOUT);
});

View File

@ -84,6 +84,21 @@ describe("Abilities - Gulp Missile", () => {
expect(cramorant.formIndex).toBe(GORGING_FORM);
});
it("changes to base form when switched out after Surf or Dive is used", async () => {
await game.startBattle([Species.CRAMORANT, Species.MAGIKARP]);
const cramorant = game.scene.getPlayerPokemon()!;
game.doAttack(getMovePosition(game.scene, 0, Moves.SURF));
await game.toNextTurn();
game.doSwitchPokemon(1);
await game.toNextTurn(); // form change is delayed until after end of turn
expect(cramorant.formIndex).toBe(NORMAL_FORM);
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeUndefined();
expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeUndefined();
});
it("changes form during Dive's charge turn", async () => {
await game.startBattle([Species.CRAMORANT]);
const cramorant = game.scene.getPlayerPokemon()!;

View File

@ -15,6 +15,7 @@ import {
MovePhase,
NewBattlePhase,
NextEncounterPhase,
PartyHealPhase,
PostSummonPhase,
SelectGenderPhase,
SelectModifierPhase,
@ -92,6 +93,7 @@ export default class PhaseInterceptor {
[QuietFormChangePhase, this.startPhase],
[SwitchPhase, this.startPhase],
[SwitchSummonPhase, this.startPhase],
[PartyHealPhase, this.startPhase],
];
private endBySetMode = [

View File

@ -2295,13 +2295,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
container.cost = this.scene.gameData.getSpeciesStarterValue(container.species.speciesId);
// First, ensure you have the caught attributes for the species else default to bigint 0
const caughtVariants = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
const isCaught = this.scene.gameData.dexData[container.species.speciesId]?.caughtAttr || BigInt(0);
// Define the variables based on whether their respective variants have been caught
const isVariant3Caught = !!(caughtVariants & DexAttr.VARIANT_3);
const isVariant2Caught = !!(caughtVariants & DexAttr.VARIANT_2);
const isVariantCaught = !!(caughtVariants & DexAttr.SHINY);
const isCaught = !!(caughtVariants & DexAttr.NON_SHINY);
const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3);
const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2);
const isVariantCaught = !!(isCaught & DexAttr.SHINY);
const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught;
const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0;
const isPassiveUnlockable = this.isPassiveAvailable(container.species.speciesId) && !isPassiveUnlocked;
@ -2913,6 +2912,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (species) {
const dexEntry = this.scene.gameData.dexData[species.speciesId];
const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr;
const isCaught = this.scene.gameData.dexData[species.speciesId]?.caughtAttr || BigInt(0);
const isVariant3Caught = !!(isCaught & DexAttr.VARIANT_3);
const isVariant2Caught = !!(isCaught & DexAttr.VARIANT_2);
const isVariantCaught = !!(isCaught & DexAttr.SHINY);
const isMaleCaught = !!(isCaught & DexAttr.MALE);
const isFemaleCaught = !!(isCaught & DexAttr.FEMALE);
if (!dexEntry.caughtAttr) {
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId));
const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
@ -2975,8 +2982,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant));
currentFilteredContainer.checkIconId(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.canCycleShiny = isVariantCaught || isVariant2Caught || isVariant3Caught;
this.canCycleGender = isMaleCaught && isFemaleCaught;
this.canCycleAbility = [ abilityAttr & AbilityAttr.ABILITY_1, (abilityAttr & AbilityAttr.ABILITY_2) && species.ability2, abilityAttr & AbilityAttr.ABILITY_HIDDEN ].filter(a => a).length > 1;
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
.map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1;
@ -2985,7 +2993,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
if (dexEntry.caughtAttr && species.malePercent !== null) {
const gender = !female ? Gender.MALE : Gender.FEMALE;
let gender: Gender;
if ((female && isFemaleCaught) || (!female && !isMaleCaught)) {
gender = Gender.FEMALE;
} else {
gender = Gender.MALE;
}
this.pokemonGenderText.setText(getGenderSymbol(gender));
this.pokemonGenderText.setColor(getGenderColor(gender));
this.pokemonGenderText.setShadowColor(getGenderColor(gender, true));