finish absolute avarice encounter

This commit is contained in:
ImperialSympathizer 2024-07-26 23:02:15 -04:00
parent b31a23e401
commit 7b2f21dc8c
8 changed files with 312 additions and 160 deletions

View File

@ -1,21 +1,26 @@
import { EnemyPartyConfig, generateModifierTypeOption, leaveEncounterWithoutBattle, updatePlayerMoney, } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards, transitionMysteryEncounterIntroVisuals, } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import Pokemon from "#app/field/pokemon"; import Pokemon, { PokemonMove } from "#app/field/pokemon";
import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { BerryModifierType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import BattleScene from "#app/battle-scene"; import BattleScene from "#app/battle-scene";
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import { MoneyRequirement, PersistentModifierRequirement } from "../mystery-encounter-requirements"; import { PersistentModifierRequirement } from "../mystery-encounter-requirements";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { BerryModifier } from "#app/modifier/modifier"; import { BerryModifier } from "#app/modifier/modifier";
import { ModifierRewardPhase, StatChangePhase } from "#app/phases"; import { StatChangePhase } from "#app/phases";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BattleStat } from "#app/data/battle-stat"; import { BattleStat } from "#app/data/battle-stat";
import { randInt } from "#app/utils";
import { BattlerIndex } from "#app/battle";
import { applyModifierTypeToPlayerPokemon, catchPokemon, getHighestLevelPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { TrainerSlot } from "#app/data/trainer-config";
import { PokeballType } from "#app/data/pokeball";
/** the i18n namespace for this encounter */ /** the i18n namespace for this encounter */
const namespace = "mysteryEncounter:absoluteAvarice"; const namespace = "mysteryEncounter:absoluteAvarice";
@ -92,15 +97,6 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
hidden: true, hidden: true,
disableAnimation: true disableAnimation: true
}, },
{
spriteKey: "petaya_berry",
fileRoot: "items",
isItem: true,
x: 20,
y: -17,
hidden: true,
disableAnimation: true
},
{ {
spriteKey: "enigma_berry", spriteKey: "enigma_berry",
fileRoot: "items", fileRoot: "items",
@ -119,6 +115,15 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
hidden: true, hidden: true,
disableAnimation: true disableAnimation: true
}, },
{
spriteKey: "petaya_berry",
fileRoot: "items",
isItem: true,
x: 30,
y: -17,
hidden: true,
disableAnimation: true
},
{ {
spriteKey: "ganlon_berry", spriteKey: "ganlon_berry",
fileRoot: "items", fileRoot: "items",
@ -136,7 +141,8 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
y: -2, y: -2,
hidden: true, hidden: true,
disableAnimation: true disableAnimation: true
}, { },
{
spriteKey: "starf_berry", spriteKey: "starf_berry",
fileRoot: "items", fileRoot: "items",
isItem: true, isItem: true,
@ -146,92 +152,11 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
disableAnimation: true disableAnimation: true
}, },
]) ])
.withHideWildIntroMessage(true)
.withAutoHideIntroVisuals(false)
.withOnVisualsStart((scene: BattleScene) => { .withOnVisualsStart((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter; doGreedentSpriteSteal(scene);
const greedentSprites = encounter.introVisuals.getSpriteAtIndex(0); doBerrySpritePile(scene);
scene.playSound("Follow Me");
// scene.tweens.add({
// targets: greedentSprites,
// duration: 600,
// ease: "Cubic.easeOut",
// yoyo: true,
// y: "+=50",
// x: "-=60",
// scale: 1.2,
// onComplete: () => {
// // Bounce the Greedent
// scene.tweens.add({
// targets: greedentSprites,
// duration: 300,
// ease: "Cubic.easeOut",
// yoyo: true,
// y: "-=20",
// loop: 1,
// });
// }
// });
// Slide left
scene.tweens.add({
targets: greedentSprites,
duration: 500,
ease: "Cubic.easeOut",
x: "-=300",
onComplete: () => {
// Slide back right, lower
greedentSprites[0].y += 80;
greedentSprites[1].y += 80;
scene.tweens.add({
targets: greedentSprites,
duration: 300,
ease: "Cubic.easeOut",
yoyo: true,
x: "+=140",
onComplete: () => {
// Slide back right, higher
greedentSprites[0].y -= 80;
greedentSprites[1].y -= 80;
scene.tweens.add({
targets: greedentSprites,
duration: 500,
ease: "Cubic.easeOut",
x: "+=300",
onComplete: () => {
// Bounce the Greedent
scene.tweens.add({
targets: greedentSprites,
duration: 300,
ease: "Cubic.easeOut",
yoyo: true,
y: "-=20",
loop: 1,
});
}
});
}
});
}
});
const berryAddDelay = 200;
const animationOrder = ["starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa"];
animationOrder.forEach((berry, i) => {
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey.includes(berry));
const [ sprite, tintSprite ] = encounter.introVisuals.getSpriteAtIndex(introVisualsIndex);
// const [ sprite, tintSprite ] = [berrySprites[i * 2], berrySprites[i * 2 + 1]];
scene.time.delayedCall(berryAddDelay * i + 300, () => {
if (sprite) {
sprite.setVisible(true);
}
if (tintSprite) {
tintSprite.setVisible(true);
}
});
});
return true; return true;
}) })
@ -251,8 +176,8 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
scene.loadSe("PRSFX- Bug Bite", "battle_anims");
scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3"); scene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
// scene.loadSe("Follow Me", "battle_anims");
// Get all player berry items, remove from party, and store reference // Get all player berry items, remove from party, and store reference
const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[]; const berryItems = scene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
@ -288,13 +213,13 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
{ {
species: getPokemonSpecies(Species.GREEDENT), species: getPokemonSpecies(Species.GREEDENT),
isBoss: true, isBoss: true,
bossSegments: 5, bossSegments: 3,
// nature: Nature.BOLD, // nature: Nature.BOLD,
moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF], moveSet: [Moves.THRASH, Moves.BODY_PRESS, Moves.STUFF_CHEEKS, Moves.SLACK_OFF],
modifierTypes: bossModifierTypes, modifierTypes: bossModifierTypes,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(pokemon.scene, `${namespace}:option:2:stat_boost`); queueEncounterMessage(pokemon.scene, `${namespace}:option:1:boss_enraged`);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1)); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD], 1));
} }
} }
@ -317,15 +242,32 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
}, },
], ],
}) })
.withPreOptionPhase(async (scene: BattleScene): Promise<boolean> => {
const encounter = scene.currentBattle.mysteryEncounter;
updatePlayerMoney(scene, -(encounter.options[0].requirements[0] as MoneyRequirement).requiredMoney, true, false);
return true;
})
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
// Give the player an Ability Charm // Pick battle
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.ABILITY_CHARM)); const encounter = scene.currentBattle.mysteryEncounter;
leaveEncounterWithoutBattle(scene, true);
// Provides 1x Reviver Seed to each party member at end of battle
const revSeed = generateModifierTypeOption(scene, modifierTypes.REVIVER_SEED).type;
const givePartyPokemonReviverSeeds = () => {
const party = scene.getParty();
party.forEach(p => {
const seedModifier = revSeed.newModifier(p);
scene.addModifier(seedModifier, false, false, false, true);
});
queueEncounterMessage(scene, `${namespace}:option:1:food_stash`);
};
setEncounterRewards(scene, { fillRemaining: true }, null, givePartyPokemonReviverSeeds);
encounter.startOfBattleEffects.push(
{
sourceBattlerIndex: BattlerIndex.ENEMY,
targets: [BattlerIndex.ENEMY],
move: new PokemonMove(Moves.STUFF_CHEEKS),
ignorePp: true
});
transitionMysteryEncounterIntroVisuals(scene, true, true, 500);
await initBattleWithEnemyConfig(scene, encounter.enemyPartyConfigs[0]);
}) })
.build() .build()
) )
@ -335,7 +277,6 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}:option:2:label`, buttonLabel: `${namespace}:option:2:label`,
buttonTooltip: `${namespace}:option:2:tooltip`, buttonTooltip: `${namespace}:option:2:tooltip`,
secondOptionPrompt: `${namespace}:option:2:select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}:option:2:selected`, text: `${namespace}:option:2:selected`,
@ -344,19 +285,27 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
}) })
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter; const encounter = scene.currentBattle.mysteryEncounter;
const modifier = encounter.misc.chosenModifier; const berryMap = encounter.misc.berryItemsMap;
// Give the player a Candy Jar if they gave a Berry, and a Healing Charm for Reviver Seed
if (modifier.type.name.includes("Berry")) {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.CANDY_JAR));
} else {
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.HEALING_CHARM));
}
// Remove the modifier if its stacks go to 0 // Returns 2/5 of the berries stolen from each Pokemon
modifier.stackCount -= 1; const party = scene.getParty();
if (modifier.stackCount === 0) { party.forEach(pokemon => {
scene.removeModifier(modifier); const stolenBerries: BerryModifier[] = berryMap.get(pokemon.id);
} const berryTypesAsArray = [];
stolenBerries?.forEach(bMod => berryTypesAsArray.push(...new Array(bMod.stackCount).fill(bMod.berryType)));
const returnedBerryCount = Math.floor((berryTypesAsArray.length ?? 0) * 2 / 5);
if (returnedBerryCount > 0) {
for (let i = 0; i < returnedBerryCount; i++) {
// Shuffle remaining berry types and pop
Phaser.Math.RND.shuffle(berryTypesAsArray);
const randBerryType = berryTypesAsArray.pop();
const berryModType = generateModifierTypeOption(scene, modifierTypes.BERRY, [randBerryType]).type as BerryModifierType;
applyModifierTypeToPlayerPokemon(scene, pokemon, berryModType);
}
}
});
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
@ -368,27 +317,196 @@ export const AbsoluteAvariceEncounter: IMysteryEncounter =
.withDialogue({ .withDialogue({
buttonLabel: `${namespace}:option:3:label`, buttonLabel: `${namespace}:option:3:label`,
buttonTooltip: `${namespace}:option:3:tooltip`, buttonTooltip: `${namespace}:option:3:tooltip`,
secondOptionPrompt: `${namespace}:option:3:select_prompt`,
selected: [ selected: [
{ {
text: `${namespace}:option:3:selected`, text: `${namespace}:option:3:selected`,
}, },
], ],
}) })
.withPreOptionPhase(async (scene: BattleScene) => {
// Animate berries being eaten
doGreedentEatBerries(scene);
doBerrySpritePile(scene, true);
return true;
})
.withOptionPhase(async (scene: BattleScene) => { .withOptionPhase(async (scene: BattleScene) => {
const encounter = scene.currentBattle.mysteryEncounter; // Let it have the food
const modifier = encounter.misc.chosenModifier; // Greedent joins the team, level equal to 2 below highest party member
// Give the player a Berry Pouch const level = getHighestLevelPlayerPokemon(scene).level;
scene.unshiftPhase(new ModifierRewardPhase(scene, modifierTypes.BERRY_POUCH)); const greedent = scene.addEnemyPokemon(getPokemonSpecies(Species.GREEDENT), level, TrainerSlot.NONE, false);
greedent.moveset = [new PokemonMove(Moves.THRASH), new PokemonMove(Moves.BODY_PRESS), new PokemonMove(Moves.STUFF_CHEEKS), new PokemonMove(Moves.SLACK_OFF)];
// Remove the modifier if its stacks go to 0 greedent.passive = true;
modifier.stackCount -= 1;
if (modifier.stackCount === 0) {
scene.removeModifier(modifier);
}
await catchPokemon(scene, greedent, null, PokeballType.POKEBALL, false);
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })
.build() .build()
) )
.build(); .build();
function doGreedentSpriteSteal(scene: BattleScene) {
const shakeDelay = 50;
const slideDelay = 500;
const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals.getSpriteAtIndex(0);
scene.playSound("Follow Me");
scene.tweens.chain({
targets: greedentSprites,
tweens: [
{ // Slide Greedent diagonally
duration: slideDelay,
ease: "Cubic.easeOut",
y: "+=75",
x: "-=65",
scale: 1.1
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Shake
duration: shakeDelay,
ease: "Cubic.easeOut",
yoyo: true,
x: (randInt(2) > 0 ? "-=" : "+=") + 5,
y: (randInt(2) > 0 ? "-=" : "+=") + 5,
},
{ // Slide Greedent diagonally
duration: slideDelay,
ease: "Cubic.easeOut",
y: "-=75",
x: "+=65",
scale: 1
},
{ // Bounce at the end
duration: 300,
ease: "Cubic.easeOut",
yoyo: true,
y: "-=20",
loop: 1,
}
]
});
}
function doGreedentEatBerries(scene: BattleScene) {
const greedentSprites = scene.currentBattle.mysteryEncounter.introVisuals.getSpriteAtIndex(0);
// scene.playSound("Follow Me");
let index = 1;
scene.tweens.add({
targets: greedentSprites,
duration: 150,
ease: "Cubic.easeOut",
yoyo: true,
y: "-=8",
loop: 5,
onStart: () => {
scene.playSound("PRSFX- Bug Bite");
},
onLoop: () => {
if (index % 2 === 0) {
scene.playSound("PRSFX- Bug Bite");
}
index++;
}
});
}
/**
*
* @param scene
* @param isEat - default false. Will "create" pile when false, and remove pile when true.
*/
function doBerrySpritePile(scene: BattleScene, isEat: boolean = false) {
const berryAddDelay = 150;
let animationOrder = ["starf", "sitrus", "lansat", "salac", "apicot", "enigma", "liechi", "ganlon", "lum", "petaya", "leppa"];
if (isEat) {
animationOrder = animationOrder.reverse();
}
const encounter = scene.currentBattle.mysteryEncounter;
animationOrder.forEach((berry, i) => {
const introVisualsIndex = encounter.spriteConfigs.findIndex(config => config.spriteKey.includes(berry));
const [ sprite, tintSprite ] = encounter.introVisuals.getSpriteAtIndex(introVisualsIndex);
scene.time.delayedCall(berryAddDelay * i + 400, () => {
if (sprite) {
sprite.setVisible(!isEat);
}
if (tintSprite) {
tintSprite.setVisible(!isEat);
}
// Animate Petaya berry falling off the pile
if (berry === "petaya" && sprite && tintSprite && !isEat) {
scene.time.delayedCall(200, () => {
doBerryBounce(scene, [sprite, tintSprite], 30, 500);
});
}
});
});
}
function doBerryBounce(scene: BattleScene, berrySprites: Phaser.GameObjects.Sprite[], yd: number, baseBounceDuration: integer) {
let bouncePower = 1;
let bounceYOffset = yd;
const doBounce = () => {
scene.tweens.add({
targets: berrySprites,
y: "+=" + bounceYOffset,
x: { value: "+=" + (bouncePower * bouncePower * 10), ease: "Linear" },
duration: bouncePower * baseBounceDuration,
ease: "Cubic.easeIn",
onComplete: () => {
bouncePower = bouncePower > 0.01 ? bouncePower * 0.5 : 0;
if (bouncePower) {
bounceYOffset = bounceYOffset * bouncePower;
scene.tweens.add({
targets: berrySprites,
y: "-=" + bounceYOffset,
x: { value: "+=" + (bouncePower * bouncePower * 10), ease: "Linear" },
duration: bouncePower * baseBounceDuration,
ease: "Cubic.easeOut",
onComplete: () => doBounce()
});
}
}
});
};
doBounce();
}

View File

@ -1,6 +1,6 @@
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { EnemyPartyConfig, generateModifierTypeOption, initBattleWithEnemyConfig, initCustomMovesForEncounter, leaveEncounterWithoutBattle, setEncounterExp, setEncounterRewards, transitionMysteryEncounterIntroVisuals } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { modifierTypes, } from "#app/modifier/modifier-type"; import { AttackTypeBoosterModifierType, modifierTypes, } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import BattleScene from "#app/battle-scene"; import BattleScene from "#app/battle-scene";
import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter"; import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter";
@ -17,7 +17,7 @@ import { WeatherType } from "#app/data/weather";
import { isNullOrUndefined, randSeedInt } from "#app/utils"; import { isNullOrUndefined, randSeedInt } from "#app/utils";
import { StatusEffect } from "#app/data/status-effect"; import { StatusEffect } from "#app/data/status-effect";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { applyDamageToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
@ -246,9 +246,8 @@ function giveLeadPokemonCharcoal(scene: BattleScene) {
// Give first party pokemon Charcoal for free at end of battle // Give first party pokemon Charcoal for free at end of battle
const leadPokemon = scene.getParty()?.[0]; const leadPokemon = scene.getParty()?.[0];
if (leadPokemon) { if (leadPokemon) {
const charcoal = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]); const charcoal = generateModifierTypeOption(scene, modifierTypes.ATTACK_TYPE_BOOSTER, [Type.FIRE]).type as AttackTypeBoosterModifierType;
scene.addModifier(charcoal.type.newModifier(leadPokemon), true); applyModifierTypeToPlayerPokemon(scene, leadPokemon, charcoal);
scene.updateModifiers();
scene.currentBattle.mysteryEncounter.setDialogueToken("leadPokemon", leadPokemon.name); scene.currentBattle.mysteryEncounter.setDialogueToken("leadPokemon", leadPokemon.name);
queueEncounterMessage(scene, `${namespace}:found_charcoal`); queueEncounterMessage(scene, `${namespace}:found_charcoal`);
} }

View File

@ -133,7 +133,7 @@ export const PokemonSalesmanEncounter: IMysteryEncounter =
// "Catch" purchased pokemon // "Catch" purchased pokemon
const data = new PokemonData(purchasedPokemon); const data = new PokemonData(purchasedPokemon);
data.player = false; data.player = false;
await catchPokemon(scene, data.toPokemon(scene) as EnemyPokemon, null, PokeballType.POKEBALL, true); await catchPokemon(scene, data.toPokemon(scene) as EnemyPokemon, null, PokeballType.POKEBALL, true, true);
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
}) })

View File

@ -10,7 +10,7 @@ import IMysteryEncounter, { MysteryEncounterBuilder } from "../mystery-encounter
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
import { MoneyRequirement } from "../mystery-encounter-requirements"; import { MoneyRequirement } from "../mystery-encounter-requirements";
import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText, queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { applyDamageToPokemon, applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
@ -110,10 +110,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
const modifiers = encounter.misc.modifiers; const modifiers = encounter.misc.modifiers;
for (const modType of modifiers) { for (const modType of modifiers) {
const modifier = modType.newModifier(chosenPokemon); await applyModifierTypeToPlayerPokemon(scene, chosenPokemon, modType);
await scene.addModifier(modifier, true, false, false, true);
} }
scene.updateModifiers(true);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
}) })
@ -195,10 +193,8 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
const modifiers = encounter.misc.modifiers; const modifiers = encounter.misc.modifiers;
for (const modType of modifiers) { for (const modType of modifiers) {
const modifier = modType.newModifier(chosenPokemon); await applyModifierTypeToPlayerPokemon(scene, chosenPokemon, modType);
await scene.addModifier(modifier, true, false, false, true);
} }
scene.updateModifiers(true);
leaveEncounterWithoutBattle(scene); leaveEncounterWithoutBattle(scene);
}) })

View File

@ -167,13 +167,13 @@ export default class IMysteryEncounter implements IMysteryEncounter {
this.requirements = this.requirements ? this.requirements : []; this.requirements = this.requirements ? this.requirements : [];
this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false; this.hideBattleIntroMessage = !isNullOrUndefined(this.hideBattleIntroMessage) ? this.hideBattleIntroMessage : false;
this.autoHideIntroVisuals = !isNullOrUndefined(this.autoHideIntroVisuals) ? this.autoHideIntroVisuals : true; this.autoHideIntroVisuals = !isNullOrUndefined(this.autoHideIntroVisuals) ? this.autoHideIntroVisuals : true;
this.startOfBattleEffects = this.startOfBattleEffects ?? [];
// Reset any dirty flags or encounter data // Reset any dirty flags or encounter data
this.startOfBattleEffectsComplete = false; this.startOfBattleEffectsComplete = false;
this.lockEncounterRewardTiers = true; this.lockEncounterRewardTiers = true;
this.dialogueTokens = {}; this.dialogueTokens = {};
this.enemyPartyConfigs = []; this.enemyPartyConfigs = [];
this.startOfBattleEffects = [];
this.introVisuals = null; this.introVisuals = null;
this.misc = null; this.misc = null;
this.expMultiplier = 1; this.expMultiplier = 1;

View File

@ -17,7 +17,7 @@ import { Type } from "#app/data/type";
import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "#app/data/pokemon-species";
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
export interface MysteryEncounterPokemonData { export interface MysteryEncounterPokemonData {
spriteScale?: number spriteScale?: number
@ -233,6 +233,36 @@ export async function modifyPlayerPokemonBST(pokemon: PlayerPokemon, value: numb
pokemon.calculateStats(); pokemon.calculateStats();
} }
/**
* Will attempt to add a new modifier to a Pokemon.
* If the Pokemon already has max stacks of that item, it will instead apply 'fallbackModifierType', if specified.
* @param scene
* @param pokemon
* @param modType
* @param fallbackModifierType
*/
export async function applyModifierTypeToPlayerPokemon(scene: BattleScene, pokemon: PlayerPokemon, modType: PokemonHeldItemModifierType, fallbackModifierType?: PokemonHeldItemModifierType) {
// Check if the Pokemon has max stacks of that item already
const existing = scene.findModifier(m => (
m instanceof PokemonHeldItemModifier &&
m.type.id === modType.id &&
m.pokemonId === pokemon.id
)) as PokemonHeldItemModifier;
// At max stacks
if (existing && existing.getStackCount() >= existing.getMaxStackCount(scene)) {
if (!fallbackModifierType) {
return;
}
// Apply fallback
return applyModifierTypeToPlayerPokemon(scene, pokemon, fallbackModifierType);
}
const modifier = modType.newModifier(pokemon);
await scene.addModifier(modifier, false, false, false, true);
}
/** /**
* Alternative to using AttemptCapturePhase * Alternative to using AttemptCapturePhase
* Assumes player sprite is visible on the screen (this is intended for non-combat uses) * Assumes player sprite is visible on the screen (this is intended for non-combat uses)
@ -407,7 +437,7 @@ function failCatch(scene: BattleScene, pokemon: EnemyPokemon, originalY: number,
}); });
} }
export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType, isObtain: boolean = false): Promise<void> { export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, pokeball: Phaser.GameObjects.Sprite, pokeballType: PokeballType, showCatchObtainMessage: boolean = true, isObtain: boolean = false): Promise<void> {
scene.unshiftPhase(new VictoryPhase(scene, BattlerIndex.ENEMY)); scene.unshiftPhase(new VictoryPhase(scene, BattlerIndex.ENEMY));
const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm(); const speciesForm = !pokemon.fusionSpecies ? pokemon.getSpeciesForm() : pokemon.getFusionSpeciesForm();
@ -433,7 +463,7 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs); scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs);
return new Promise(resolve => { return new Promise(resolve => {
scene.ui.showText(i18next.t(isObtain ? "battle:pokemonObtained" : "battle:pokemonCaught", { pokemonName: pokemon.name }), null, () => { const doPokemonCatchMenu = () => {
const end = () => { const end = () => {
scene.pokemonInfoContainer.hide(); scene.pokemonInfoContainer.hide();
removePb(scene, pokeball); removePb(scene, pokeball);
@ -488,7 +518,13 @@ export async function catchPokemon(scene: BattleScene, pokemon: EnemyPokemon, po
addToParty(); addToParty();
} }
}); });
}, 0, true); };
if (showCatchObtainMessage) {
scene.ui.showText(i18next.t(isObtain ? "battle:pokemonObtained" : "battle:pokemonCaught", { pokemonName: pokemon.name }), null, doPokemonCatchMenu, 0, true);
} else {
doPokemonCatchMenu();
}
}); });
} }

View File

@ -7,7 +7,10 @@ export const absoluteAvariceDialogue = {
1: { 1: {
label: "Battle It", label: "Battle It",
tooltip: "(-) Tough Battle\n(+) Rewards from its Berry Hoard", tooltip: "(-) Tough Battle\n(+) Rewards from its Berry Hoard",
selected: "You'll show this Greedent what\nhappens to those who steal from you!", selected: "The Greedent stuffs its cheeks\nand prepares for battle!",
boss_enraged: "Greedent's fierce love for food has it incensed!",
food_stash: `It looks like the Greedent was guarding an enormous stash of food!
$@s{item_fanfare}Each Pokémon in your party gains 1x Reviver Seed!`
}, },
2: { 2: {
label: "Reason with It", label: "Reason with It",
@ -18,10 +21,10 @@ export const absoluteAvariceDialogue = {
3: { 3: {
label: "Let It Have the Food", label: "Let It Have the Food",
tooltip: "(-) Lose All Berries\n(?) The Greedent Will Like You", tooltip: "(-) Lose All Berries\n(?) The Greedent Will Like You",
selected: `The Greedent devours the entire stash of berries in a flash! selected: `The Greedent devours the entire\nstash of berries in a flash!
$Patting its stomach, it looks at you appreciatively. $Patting its stomach,\nit looks at you appreciatively.
$Perhaps you could feed it more berries on your adventure... $Perhaps you could feed it\nmore berries on your adventure...
$The Greedent wants to join your party!`, $@s{level_up_fanfare}The Greedent wants to join your party!`,
}, },
} }
}; };

View File

@ -117,9 +117,9 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
*/ */
// 1 to 256, set to null to ignore // 1 to 256, set to null to ignore
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null; export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null; export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null; export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.ABSOLUTE_AVARICE;
/** /**
* MODIFIER / ITEM OVERRIDES * MODIFIER / ITEM OVERRIDES