[ME] Show shiny sparkles for Pokemon in ME intro

This commit is contained in:
Moka 2024-11-09 00:11:01 +01:00
parent 772594e26e
commit 8ed40dd0c8
6 changed files with 94 additions and 11 deletions

View File

@ -98,7 +98,9 @@ export const BerriesAboundEncounter: MysteryEncounter =
tint: 0.25, tint: 0.25,
x: -5, x: -5,
repeat: true, repeat: true,
isPokemon: true isPokemon: true,
isShiny: bossPokemon.shiny,
variant: bossPokemon.variant
} }
]; ];

View File

@ -114,7 +114,9 @@ export const FightOrFlightEncounter: MysteryEncounter =
tint: 0.25, tint: 0.25,
x: -5, x: -5,
repeat: true, repeat: true,
isPokemon: true isPokemon: true,
isShiny: bossPokemon.shiny,
variant: bossPokemon.variant
}, },
]; ];

View File

@ -85,7 +85,9 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter =
fileRoot: fileRoot, fileRoot: fileRoot,
hasShadow: true, hasShadow: true,
repeat: true, repeat: true,
isPokemon: true isPokemon: true,
isShiny: pokemon.shiny,
variant: pokemon.variant
}); });
const starterTier = speciesStarterCosts[species.speciesId]; const starterTier = speciesStarterCosts[species.speciesId];

View File

@ -100,7 +100,9 @@ export const UncommonBreedEncounter: MysteryEncounter =
hasShadow: true, hasShadow: true,
x: -5, x: -5,
repeat: true, repeat: true,
isPokemon: true isPokemon: true,
isShiny: pokemon.shiny,
variant: pokemon.variant
}, },
]; ];
@ -113,13 +115,17 @@ export const UncommonBreedEncounter: MysteryEncounter =
const encounter = scene.currentBattle.mysteryEncounter!; const encounter = scene.currentBattle.mysteryEncounter!;
const pokemonSprite = encounter.introVisuals!.getSprites(); const pokemonSprite = encounter.introVisuals!.getSprites();
scene.tweens.add({ // Bounce at the end // Bounce at the end, then shiny sparkle if the Pokemon is shiny
scene.tweens.add({
targets: pokemonSprite, targets: pokemonSprite,
duration: 300, duration: 300,
ease: "Cubic.easeOut", ease: "Cubic.easeOut",
yoyo: true, yoyo: true,
y: "-=20", y: "-=20",
loop: 1, loop: 1,
onComplete: () => {
encounter.introVisuals?.playShinySparkles();
}
}); });
scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2")); scene.time.delayedCall(500, () => scene.playSound("battle_anims/PRSFX- Spotlight2"));

View File

@ -5,6 +5,7 @@ import { Species } from "#enums/species";
import { isNullOrUndefined } from "#app/utils"; import { isNullOrUndefined } from "#app/utils";
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import PlayAnimationConfig = Phaser.Types.Animations.PlayAnimationConfig; import PlayAnimationConfig = Phaser.Types.Animations.PlayAnimationConfig;
import { Variant, variantColorCache, variantData, VariantSet } from "#app/data/variant";
type KnownFileRoot = type KnownFileRoot =
| "arenas" | "arenas"
@ -59,6 +60,9 @@ export class MysteryEncounterSpriteConfig {
scale?: number; scale?: number;
/** If you are using a Pokemon sprite, set to `true`. This will ensure variant, form, gender, shiny sprites are loaded properly */ /** If you are using a Pokemon sprite, set to `true`. This will ensure variant, form, gender, shiny sprites are loaded properly */
isPokemon?: boolean; isPokemon?: boolean;
//TODO
isShiny?: boolean;
variant?: Variant;
/** If you are using an item sprite, set to `true` */ /** If you are using an item sprite, set to `true` */
isItem?: boolean; isItem?: boolean;
/** The sprites alpha. `0` - `1` The lower the number, the more transparent */ /** The sprites alpha. `0` - `1` The lower the number, the more transparent */
@ -74,9 +78,12 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
public encounter: MysteryEncounter; public encounter: MysteryEncounter;
public spriteConfigs: MysteryEncounterSpriteConfig[]; public spriteConfigs: MysteryEncounterSpriteConfig[];
public enterFromRight: boolean; public enterFromRight: boolean;
private shinySparkleSprites: { sprite: Phaser.GameObjects.Sprite, variant: Variant }[];
constructor(scene: BattleScene, encounter: MysteryEncounter) { constructor(scene: BattleScene, encounter: MysteryEncounter) {
super(scene, -72, 76); super(scene, -72, 76);
this.shinySparkleSprites = [];
this.encounter = encounter; this.encounter = encounter;
this.enterFromRight = encounter.enterIntroVisualsFromRight ?? false; this.enterFromRight = encounter.enterIntroVisualsFromRight ?? false;
// Shallow copy configs to allow visual config updates at runtime without dirtying master copy of Encounter // Shallow copy configs to allow visual config updates at runtime without dirtying master copy of Encounter
@ -86,7 +93,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
}; };
if (!isNullOrUndefined(result.species)) { if (!isNullOrUndefined(result.species)) {
const keys = getSpriteKeysFromSpecies(result.species); const keys = getSpriteKeysFromSpecies(result.species, undefined, undefined, result.isShiny, result.variant);
result.spriteKey = keys.spriteKey; result.spriteKey = keys.spriteKey;
result.fileRoot = keys.fileRoot; result.fileRoot = keys.fileRoot;
result.isPokemon = true; result.isPokemon = true;
@ -120,18 +127,35 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
// Sprites with custom X or Y defined will not count for normal spacing requirements // 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)); const spacingValue = Math.round((maxX - minX) / Math.max(this.spriteConfigs.filter(s => !s.x && !s.y).length, 1));
const shinySparkleSprites = scene.add.container(0, 0);
this.spriteConfigs?.forEach((config) => { this.spriteConfigs?.forEach((config) => {
const { spriteKey, isItem, hasShadow, scale, x, y, yShadow, alpha } = config; const { spriteKey, isItem, hasShadow, scale, x, y, yShadow, alpha, isPokemon, isShiny, variant } = config;
let sprite: GameObjects.Sprite; let sprite: GameObjects.Sprite;
let tintSprite: GameObjects.Sprite; let tintSprite: GameObjects.Sprite;
let pokemonShinySparkle: Phaser.GameObjects.Sprite | undefined;
if (!isItem) { if (isItem) {
sprite = getSprite(spriteKey, hasShadow, yShadow);
tintSprite = getSprite(spriteKey);
} else {
sprite = getItemSprite(spriteKey, hasShadow, yShadow); sprite = getItemSprite(spriteKey, hasShadow, yShadow);
tintSprite = getItemSprite(spriteKey); tintSprite = getItemSprite(spriteKey);
} else {
sprite = getSprite(spriteKey, hasShadow, yShadow);
tintSprite = getSprite(spriteKey);
if (isPokemon && isShiny) {
// Set Pipeline for shiny variant
sprite.setPipelineData("spriteKey", spriteKey);
tintSprite.setPipelineData("spriteKey", spriteKey);
sprite.setPipelineData("shiny", true);
sprite.setPipelineData("variant", variant);
tintSprite.setPipelineData("shiny", true);
tintSprite.setPipelineData("variant", variant);
// Create Sprite for shiny Sparkle
pokemonShinySparkle = scene.add.sprite(sprite.x, sprite.y, "shiny");
pokemonShinySparkle.setOrigin(0.5, 1);
pokemonShinySparkle.setVisible(false);
this.shinySparkleSprites.push({ sprite: pokemonShinySparkle, variant: variant ?? 0 });
shinySparkleSprites.add(pokemonShinySparkle);
}
} }
sprite.setVisible(!config.hidden); sprite.setVisible(!config.hidden);
@ -165,6 +189,11 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
} }
} }
if (!isNullOrUndefined(pokemonShinySparkle)) {
// Offset the sparkle to match the Pokemon's position
pokemonShinySparkle.setPosition(sprite.x, sprite.y);
}
if (!isNullOrUndefined(alpha)) { if (!isNullOrUndefined(alpha)) {
sprite.setAlpha(alpha); sprite.setAlpha(alpha);
tintSprite.setAlpha(alpha); tintSprite.setAlpha(alpha);
@ -173,6 +202,7 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
this.add(sprite); this.add(sprite);
this.add(tintSprite); this.add(tintSprite);
}); });
this.add(shinySparkleSprites);
} }
/** /**
@ -187,6 +217,31 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
this.spriteConfigs.forEach((config) => { this.spriteConfigs.forEach((config) => {
if (config.isPokemon) { if (config.isPokemon) {
this.scene.loadPokemonAtlas(config.spriteKey, config.fileRoot); this.scene.loadPokemonAtlas(config.spriteKey, config.fileRoot);
if (config.isShiny) {
// Load variant assets
const useExpSprite = this.scene.experimentalSprites && this.scene.hasExpSprite(config.spriteKey);
if (useExpSprite) {
config.fileRoot = `exp/${config.fileRoot}`;
}
let variantConfig = variantData;
config.fileRoot.split("/").map(p => variantConfig ? variantConfig = variantConfig[p] : null);
const variantSet = variantConfig as VariantSet;
if (variantSet && (config.variant !== undefined && variantSet[config.variant] === 1)) {
const populateVariantColors = (key: string): Promise<void> => {
return new Promise(resolve => {
if (variantColorCache.hasOwnProperty(key)) {
return resolve();
}
this.scene.cachedFetch(`./images/pokemon/variant/${config.fileRoot}.json`).then(res => res.json()).then(c => {
variantColorCache[key] = c;
resolve();
});
});
};
populateVariantColors(config.spriteKey);
}
// TODO load shiny sparkle?
}
} else if (config.isItem) { } else if (config.isItem) {
this.scene.loadAtlas("items", ""); this.scene.loadAtlas("items", "");
} else { } else {
@ -288,6 +343,18 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
return true; return true;
} }
/**
* Play shiny sparkle animations if there are shiny Pokemon
*/
playShinySparkles() {
for (const sparkleConfig of this.shinySparkleSprites) {
this.scene.time.delayedCall(500, () => {
sparkleConfig.sprite.play(`sparkle${sparkleConfig.variant ? `_${sparkleConfig.variant + 1}` : ""}`);
this.scene.playSound("se/sparkle");
});
}
}
/** /**
* For sprites with animation and that do not have animation disabled, will begin frame animation * For sprites with animation and that do not have animation disabled, will begin frame animation
*/ */

View File

@ -204,6 +204,7 @@ export class EncounterPhase extends BattlePhase {
battle.seenEnemyPartyMemberIds.add(enemyPokemon.id); battle.seenEnemyPartyMemberIds.add(enemyPokemon.id);
const playerPokemon = this.scene.getPlayerPokemon(); const playerPokemon = this.scene.getPlayerPokemon();
if (playerPokemon?.visible) { if (playerPokemon?.visible) {
//TODO HERE
this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon); this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon);
} }
enemyPokemon.tint(0, 0.5); enemyPokemon.tint(0, 0.5);
@ -383,6 +384,9 @@ export class EncounterPhase extends BattlePhase {
if (encounter.onVisualsStart) { if (encounter.onVisualsStart) {
encounter.onVisualsStart(this.scene); encounter.onVisualsStart(this.scene);
} else if (encounter.spriteConfigs && introVisuals) {
// If the encounter doesn't have any special visual intro, show sparkle for shiny Pokemon
introVisuals.playShinySparkles();
} }
const doEncounter = () => { const doEncounter = () => {