add the strong stuff encounter

This commit is contained in:
ImperialSympathizer 2024-07-19 23:40:36 -04:00
parent b6793ea50f
commit 46f8d26100
14 changed files with 128 additions and 42 deletions

View File

@ -10,7 +10,7 @@
"scale": 1, "scale": 1,
"frames": [ "frames": [
{ {
"filename": "Bag_Berry_Juice_Sprite.png", "filename": "0001.png",
"rotated": false, "rotated": false,
"trimmed": true, "trimmed": true,
"sourceSize": { "sourceSize": {

View File

@ -28,7 +28,7 @@ export const MysteriousChestEncounter: IMysteryEncounter =
hasShadow: true, hasShadow: true,
x: 4, x: 4,
y: 10, y: 10,
yShadowOffset: 3, yShadow: 3,
disableAnimation: true, // Re-enabled after option select disableAnimation: true, // Re-enabled after option select
}, },
]) ])

View File

@ -31,7 +31,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
hasShadow: true, hasShadow: true,
x: 4, x: 4,
y: 10, y: 10,
yShadowOffset: 3 yShadow: 3
}, },
]) ])
.withIntroDialogue([ .withIntroDialogue([

View File

@ -31,7 +31,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
repeat: true, repeat: true,
x: 12, x: 12,
y: -5, y: -5,
yShadowOffset: -5 yShadow: -5
}, },
{ {
spriteKey: "b2w2_veteran_m", spriteKey: "b2w2_veteran_m",
@ -39,7 +39,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
hasShadow: true, hasShadow: true,
x: -12, x: -12,
y: 3, y: 3,
yShadowOffset: 3 yShadow: 3
}, },
]) ])
.withIntroDialogue([ .withIntroDialogue([

View File

@ -1,4 +1,4 @@
import { EnemyPartyConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { EnemyPartyConfig, hideMysteryEncounterIntroVisuals, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, setEncounterRewards } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { modifierTypes, } from "#app/modifier/modifier-type"; import { modifierTypes, } from "#app/modifier/modifier-type";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import BattleScene from "../../../battle-scene"; import BattleScene from "../../../battle-scene";
@ -6,35 +6,44 @@ import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } fro
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { Nature } from "#app/data/nature"; import { Nature } from "#app/data/nature";
import { PlayerPokemon } from "#app/field/pokemon";
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounter:oneForAll"; const namespace = "mysteryEncounter:theStrongStuff";
export const JuicedShuckleJuiceEncounter: IMysteryEncounter = export const TheStrongStuffEncounter: IMysteryEncounter =
MysteryEncounterBuilder.withEncounterType( MysteryEncounterBuilder.withEncounterType(
MysteryEncounterType.JUICED_SHUCKLE_JUICE MysteryEncounterType.THE_STRONG_STUFF
) )
.withEncounterTier(MysteryEncounterTier.COMMON) .withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180 .withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
.withHideWildIntroMessage(true) .withHideWildIntroMessage(true)
.withHideIntroVisuals(false)
.withIntroSpriteConfigs([ .withIntroSpriteConfigs([
{
spriteKey: "berry_juice",
fileRoot: "mystery-encounters",
hasShadow: true,
scale: 1.5,
x: -15,
y: 3,
yShadow: 0
},
{ {
spriteKey: Species.SHUCKLE.toString(), spriteKey: Species.SHUCKLE.toString(),
fileRoot: "pokemon", fileRoot: "pokemon",
hasShadow: true, hasShadow: true,
repeat: true, repeat: true,
scale: 2 scale: 1.5,
}, x: 20,
{ y: 10,
spriteKey: "berry_juice", yShadow: 7
fileRoot: "mystery-encounters",
hasShadow: true,
scale: 2
}, },
]) // Set in onInit() ]) // Set in onInit()
.withIntroDialogue([ .withIntroDialogue([
{ {
text: `${namespace}_intro_message`, text: `${namespace}:intro`,
}, },
]) ])
.withOnInit((scene: BattleScene) => { .withOnInit((scene: BattleScene) => {
@ -58,35 +67,39 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
return true; return true;
}) })
.withTitle(`${namespace}_title`) .withTitle(`${namespace}:title`)
.withDescription(`${namespace}_description`) .withDescription(`${namespace}:description`)
.withQuery(`${namespace}_query`) .withQuery(`${namespace}:query`)
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}_option_1_label`, buttonLabel: `${namespace}:option:1:label`,
buttonTooltip: `${namespace}_option_1_tooltip`, buttonTooltip: `${namespace}:option:1:tooltip`,
selected: [ selected: [
{ {
text: `${namespace}_option_1_selected`, text: `${namespace}:option:1:selected`
}, }
], ]
}, },
async (scene: BattleScene) => { async (scene: BattleScene) => {
// Leave encounter with no rewards or exp const encounter = scene.currentBattle.mysteryEncounter;
// const encounter = scene.currentBattle.mysteryEncounter; // Do blackout and hide intro visuals during blackout
scene.time.delayedCall(700, () => {
hideMysteryEncounterIntroVisuals(scene);
});
// -20 to all base stats of highest BST, +10 to all base stats of rest of party
// Get highest BST mon // Get highest BST mon
const party = scene.getParty(); const party = scene.getParty();
let highestBst = null; let highestBst: PlayerPokemon = null;
let statTotal = 0; let statTotal = 0;
for (const pokemon of party) { for (const pokemon of party) {
if (!highestBst) { if (!highestBst) {
highestBst = pokemon; highestBst = pokemon;
statTotal = pokemon.summonData.stats.reduce((i, n) => n + i); statTotal = pokemon.getSpeciesForm().getBaseStatTotal();
continue; continue;
} }
const total = pokemon.summonData.stats.reduce((i, n) => n + i); const total = pokemon.getSpeciesForm().getBaseStatTotal();
if (total > statTotal) { if (total > statTotal) {
highestBst = pokemon; highestBst = pokemon;
statTotal = total; statTotal = total;
@ -97,7 +110,25 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
highestBst = party[0]; highestBst = party[0];
} }
console.log("BST pre change: " + highestBst.getSpeciesForm().baseStats);
highestBst.getSpeciesForm().baseStats = [...highestBst.getSpeciesForm().baseStats].map(v => v - 20);
console.log("Species BST: " + getPokemonSpecies(highestBst.getSpeciesForm().speciesId).baseStats);
console.log("Pokemon BST: " + highestBst.getSpeciesForm().baseStats);
highestBst.calculateStats();
highestBst.updateInfo();
for (const pokemon of party) {
if (highestBst.id === pokemon.id) {
continue;
}
pokemon.getSpeciesForm().baseStats = [...pokemon.getSpeciesForm().baseStats].map(v => v + 10);
// pokemon.summonData.getSpeciesForm()Form.baseStats = pokemon.getSpeciesForm().baseStats;
pokemon.calculateStats();
pokemon.updateInfo();
}
encounter.setDialogueToken("highBstPokemon", highestBst.name);
await showEncounterText(scene, `${namespace}:option:1:selected_2`, null, true);
leaveEncounterWithoutBattle(scene, true); leaveEncounterWithoutBattle(scene, true);
return true; return true;
@ -105,11 +136,11 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
) )
.withSimpleOption( .withSimpleOption(
{ {
buttonLabel: `${namespace}_option_2_label`, buttonLabel: `${namespace}:option:2:label`,
buttonTooltip: `${namespace}_option_2_tooltip`, buttonTooltip: `${namespace}:option:2:tooltip`,
selected: [ selected: [
{ {
text: `${namespace}_option_2_selected_message`, text: `${namespace}:option:2:selected`,
}, },
], ],
}, },

View File

@ -35,7 +35,7 @@ export const TrainingSessionEncounter: IMysteryEncounter =
hasShadow: true, hasShadow: true,
y: 6, y: 6,
x: 5, x: 5,
yShadowOffset: -2 yShadow: -2
}, },
]) ])
.withIntroDialogue([ .withIntroDialogue([

View File

@ -12,6 +12,7 @@ import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax-encounte
import { TrainingSessionEncounter } from "./encounters/training-session-encounter"; import { TrainingSessionEncounter } from "./encounters/training-session-encounter";
import IMysteryEncounter from "./mystery-encounter"; import IMysteryEncounter from "./mystery-encounter";
import { SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter"; import { SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter";
import { TheStrongStuffEncounter } from "#app/data/mystery-encounters/encounters/the-strong-stuff-encounter";
// Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256 // Spawn chance: (BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT + WIGHT_INCREMENT_ON_SPAWN_MISS * <number of missed spawns>) / 256
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1; export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
@ -220,6 +221,7 @@ export function initMysteryEncounters() {
allMysteryEncounters[MysteryEncounterType.FIELD_TRIP] = FieldTripEncounter; allMysteryEncounters[MysteryEncounterType.FIELD_TRIP] = FieldTripEncounter;
allMysteryEncounters[MysteryEncounterType.SAFARI_ZONE] = SafariZoneEncounter; allMysteryEncounters[MysteryEncounterType.SAFARI_ZONE] = SafariZoneEncounter;
allMysteryEncounters[MysteryEncounterType.LOST_AT_SEA] = LostAtSeaEncounter; allMysteryEncounters[MysteryEncounterType.LOST_AT_SEA] = LostAtSeaEncounter;
allMysteryEncounters[MysteryEncounterType.THE_STRONG_STUFF] = TheStrongStuffEncounter;
// Add extreme encounters to biome map // Add extreme encounters to biome map
extremeBiomeEncounters.forEach(encounter => { extremeBiomeEncounters.forEach(encounter => {

View File

@ -221,6 +221,14 @@ export abstract class PokemonSpeciesForm {
return false; return false;
} }
/**
* Gets the BST for the species
* @returns The species' BST.
*/
getBaseStatTotal(): integer {
return this.baseStats.reduce((i, n) => n + i);
}
/** /**
* Gets the species' base stat amount for the given stat. * Gets the species' base stat amount for the given stat.
* @param stat The desired stat. * @param stat The desired stat.

View File

@ -10,5 +10,5 @@ export enum MysteryEncounterType {
FIELD_TRIP, FIELD_TRIP,
SAFARI_ZONE, SAFARI_ZONE,
LOST_AT_SEA, //might be generalized later on LOST_AT_SEA, //might be generalized later on
JUICED_SHUCKLE_JUICE THE_STRONG_STUFF
} }

View File

@ -39,7 +39,7 @@ export class MysteryEncounterSpriteConfig {
/** Y offset */ /** Y offset */
y?: number; y?: number;
/** Y shadow offset */ /** Y shadow offset */
yShadowOffset?: number; yShadow?: number;
/** Sprite scale. `0` - `n` */ /** Sprite scale. `0` - `n` */
scale?: number; scale?: number;
/** If you are using an item sprite, set to `true` */ /** If you are using an item sprite, set to `true` */
@ -70,10 +70,10 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
return; return;
} }
const getSprite = (spriteKey: string, hasShadow?: boolean, yShadowOffset?: number) => { const getSprite = (spriteKey: string, hasShadow?: boolean, yShadow?: number) => {
const ret = this.scene.addFieldSprite(0, 0, spriteKey); const ret = this.scene.addFieldSprite(0, 0, spriteKey);
ret.setOrigin(0.5, 1); ret.setOrigin(0.5, 1);
ret.setPipeline(this.scene.spritePipeline, { tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow, yShadowOffset: yShadowOffset ?? 0 }); ret.setPipeline(this.scene.spritePipeline, { tone: [0.0, 0.0, 0.0, 0.0], hasShadow: !!hasShadow, yShadowOffset: yShadow ?? 0 });
return ret; return ret;
}; };
@ -92,13 +92,13 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
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));
this.spriteConfigs?.forEach((config) => { this.spriteConfigs?.forEach((config) => {
const { spriteKey, isItem, hasShadow, scale, x, y, yShadowOffset, alpha } = config; const { spriteKey, isItem, hasShadow, scale, x, y, yShadow, alpha } = config;
let sprite: GameObjects.Sprite; let sprite: GameObjects.Sprite;
let tintSprite: GameObjects.Sprite; let tintSprite: GameObjects.Sprite;
if (!isItem) { if (!isItem) {
sprite = getSprite(spriteKey, hasShadow, yShadowOffset); sprite = getSprite(spriteKey, hasShadow, yShadow);
tintSprite = getSprite(spriteKey); tintSprite = getSprite(spriteKey);
} else { } else {
sprite = getItemSprite(spriteKey); sprite = getItemSprite(spriteKey);

View File

@ -1,4 +1,5 @@
import { lostAtSea } from "./mystery-encounters/lost-at-sea"; import { lostAtSea } from "./mystery-encounters/lost-at-sea";
import { theStrongStuffDialogue } from "#app/locales/en/mystery-encounters/the-strong-stuff-dialogue";
/** /**
* Patterns that can be used: * Patterns that can be used:
@ -241,4 +242,5 @@ export const mysteryEncounter = {
"sleeping_snorlax_option_3_good_result": "Your {{option3PrimaryName}} uses {{option3PrimaryMove}}! @s{item_fanfare}It steals Leftovers off the sleeping Snorlax and you make out like bandits!", "sleeping_snorlax_option_3_good_result": "Your {{option3PrimaryName}} uses {{option3PrimaryMove}}! @s{item_fanfare}It steals Leftovers off the sleeping Snorlax and you make out like bandits!",
lostAtSea, lostAtSea,
theStrongStuff: theStrongStuffDialogue,
} as const; } as const;

View File

@ -0,0 +1,25 @@
export const theStrongStuffDialogue = {
intro: "It's a massive Shuckle and what appears\nto be an equally large stash of... juice?",
title: "The Strong Stuff",
description: "The Shuckle that blocks your path looks incredibly strong. Meanwhile, the juice next to it is emanating power of some kind.\n\nThe Shuckle extends its feelers in your direction. It seems like it wants to touch you, but is that really a good idea?",
query: "What will you do?",
option: {
1: {
label: "Let it touch you",
tooltip: "(?) Something awful or amazing might happen",
selected: "You black out.",
selected_2: `@f{150}When you awaken, the Shuckle is gone\nand juice stash completely drained.
$Your {{highBstPokemon}} feels a\nterrible lethargy come over it!
$It's base stats were reduced by 20 in each stat!
$Your remaining Pokémon feel an incredible vigor, though!
$Their base stats are increased by 10 in each stat!`
},
2: {
label: "Battle the Shuckle",
tooltip: "(-) Hard Battle\n(+) Special Rewards",
selected:
"{{option2PrimaryName}} flies ahead of your boat, guiding you back on track.\n{{option2PrimaryName}} seems to also have gotten stronger in this time of need.",
},
},
outro: "You are back on track."
};

View File

@ -119,7 +119,7 @@ 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 = 256; 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 = MysteryEncounterType.SLEEPING_SNORLAX; export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.THE_STRONG_STUFF;
/** /**
* MODIFIER / ITEM OVERRIDES * MODIFIER / ITEM OVERRIDES

View File

@ -32,7 +32,8 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const charVarMap = new Map<integer, string>(); const charVarMap = new Map<integer, string>();
const delayMap = new Map<integer, integer>(); const delayMap = new Map<integer, integer>();
const soundMap = new Map<integer, string>(); const soundMap = new Map<integer, string>();
const actionPattern = /@(c|d|s)\{(.*?)\}/; const fadeMap = new Map<integer, integer>();
const actionPattern = /@(c|d|s|f)\{(.*?)\}/;
let actionMatch: RegExpExecArray; let actionMatch: RegExpExecArray;
while ((actionMatch = actionPattern.exec(text))) { while ((actionMatch = actionPattern.exec(text))) {
switch (actionMatch[1]) { switch (actionMatch[1]) {
@ -45,6 +46,9 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
case "s": case "s":
soundMap.set(actionMatch.index, actionMatch[2]); soundMap.set(actionMatch.index, actionMatch[2]);
break; break;
case "f":
fadeMap.set(actionMatch.index, parseInt(actionMatch[2]));
break;
} }
text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4); text = text.slice(0, actionMatch.index) + text.slice(actionMatch.index + actionMatch[2].length + 4);
} }
@ -103,6 +107,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const charVar = charVarMap.get(charIndex); const charVar = charVarMap.get(charIndex);
const charSound = soundMap.get(charIndex); const charSound = soundMap.get(charIndex);
const charDelay = delayMap.get(charIndex); const charDelay = delayMap.get(charIndex);
const charFade = fadeMap.get(charIndex);
this.message.setText(text.slice(0, charIndex)); this.message.setText(text.slice(0, charIndex));
const advance = () => { const advance = () => {
if (charVar) { if (charVar) {
@ -134,6 +139,19 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
advance(); advance();
} }
}); });
} else if (charFade) {
this.textTimer.paused = true;
this.scene.time.delayedCall(150, () => {
this.scene.ui.fadeOut(750).then(() => {
const delay = Utils.getFrameMs(charFade);
this.scene.time.delayedCall(delay, () => {
this.scene.ui.fadeIn(500).then(() => {
this.textTimer.paused = false;
advance();
});
});
});
});
} else { } else {
advance(); advance();
} }