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,
"frames": [
{
"filename": "Bag_Berry_Juice_Sprite.png",
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"sourceSize": {

View File

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

View File

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

View File

@ -31,7 +31,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
repeat: true,
x: 12,
y: -5,
yShadowOffset: -5
yShadow: -5
},
{
spriteKey: "b2w2_veteran_m",
@ -39,7 +39,7 @@ export const ShadyVitaminDealerEncounter: IMysteryEncounter =
hasShadow: true,
x: -12,
y: 3,
yShadowOffset: 3
yShadow: 3
},
])
.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 { MysteryEncounterType } from "#enums/mystery-encounter-type";
import BattleScene from "../../../battle-scene";
@ -6,35 +6,44 @@ import IMysteryEncounter, { MysteryEncounterBuilder, MysteryEncounterTier, } fro
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { Species } from "#enums/species";
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 */
const namespace = "mysteryEncounter:oneForAll";
const namespace = "mysteryEncounter:theStrongStuff";
export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
export const TheStrongStuffEncounter: IMysteryEncounter =
MysteryEncounterBuilder.withEncounterType(
MysteryEncounterType.JUICED_SHUCKLE_JUICE
MysteryEncounterType.THE_STRONG_STUFF
)
.withEncounterTier(MysteryEncounterTier.COMMON)
.withSceneWaveRangeRequirement(10, 180) // waves 10 to 180
.withHideWildIntroMessage(true)
.withHideIntroVisuals(false)
.withIntroSpriteConfigs([
{
spriteKey: "berry_juice",
fileRoot: "mystery-encounters",
hasShadow: true,
scale: 1.5,
x: -15,
y: 3,
yShadow: 0
},
{
spriteKey: Species.SHUCKLE.toString(),
fileRoot: "pokemon",
hasShadow: true,
repeat: true,
scale: 2
},
{
spriteKey: "berry_juice",
fileRoot: "mystery-encounters",
hasShadow: true,
scale: 2
scale: 1.5,
x: 20,
y: 10,
yShadow: 7
},
]) // Set in onInit()
.withIntroDialogue([
{
text: `${namespace}_intro_message`,
text: `${namespace}:intro`,
},
])
.withOnInit((scene: BattleScene) => {
@ -58,35 +67,39 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
return true;
})
.withTitle(`${namespace}_title`)
.withDescription(`${namespace}_description`)
.withQuery(`${namespace}_query`)
.withTitle(`${namespace}:title`)
.withDescription(`${namespace}:description`)
.withQuery(`${namespace}:query`)
.withSimpleOption(
{
buttonLabel: `${namespace}_option_1_label`,
buttonTooltip: `${namespace}_option_1_tooltip`,
buttonLabel: `${namespace}:option:1:label`,
buttonTooltip: `${namespace}:option:1:tooltip`,
selected: [
{
text: `${namespace}_option_1_selected`,
},
],
text: `${namespace}:option:1:selected`
}
]
},
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
const party = scene.getParty();
let highestBst = null;
let highestBst: PlayerPokemon = null;
let statTotal = 0;
for (const pokemon of party) {
if (!highestBst) {
highestBst = pokemon;
statTotal = pokemon.summonData.stats.reduce((i, n) => n + i);
statTotal = pokemon.getSpeciesForm().getBaseStatTotal();
continue;
}
const total = pokemon.summonData.stats.reduce((i, n) => n + i);
const total = pokemon.getSpeciesForm().getBaseStatTotal();
if (total > statTotal) {
highestBst = pokemon;
statTotal = total;
@ -97,7 +110,25 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
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);
return true;
@ -105,11 +136,11 @@ export const JuicedShuckleJuiceEncounter: IMysteryEncounter =
)
.withSimpleOption(
{
buttonLabel: `${namespace}_option_2_label`,
buttonTooltip: `${namespace}_option_2_tooltip`,
buttonLabel: `${namespace}:option:2:label`,
buttonTooltip: `${namespace}:option:2:tooltip`,
selected: [
{
text: `${namespace}_option_2_selected_message`,
text: `${namespace}:option:2:selected`,
},
],
},

View File

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

View File

@ -12,6 +12,7 @@ import { SleepingSnorlaxEncounter } from "./encounters/sleeping-snorlax-encounte
import { TrainingSessionEncounter } from "./encounters/training-session-encounter";
import IMysteryEncounter from "./mystery-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
export const BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT = 1;
@ -220,6 +221,7 @@ export function initMysteryEncounters() {
allMysteryEncounters[MysteryEncounterType.FIELD_TRIP] = FieldTripEncounter;
allMysteryEncounters[MysteryEncounterType.SAFARI_ZONE] = SafariZoneEncounter;
allMysteryEncounters[MysteryEncounterType.LOST_AT_SEA] = LostAtSeaEncounter;
allMysteryEncounters[MysteryEncounterType.THE_STRONG_STUFF] = TheStrongStuffEncounter;
// Add extreme encounters to biome map
extremeBiomeEncounters.forEach(encounter => {

View File

@ -221,6 +221,14 @@ export abstract class PokemonSpeciesForm {
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.
* @param stat The desired stat.

View File

@ -10,5 +10,5 @@ export enum MysteryEncounterType {
FIELD_TRIP,
SAFARI_ZONE,
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?: number;
/** Y shadow offset */
yShadowOffset?: number;
yShadow?: number;
/** Sprite scale. `0` - `n` */
scale?: number;
/** If you are using an item sprite, set to `true` */
@ -70,10 +70,10 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
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);
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;
};
@ -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));
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 tintSprite: GameObjects.Sprite;
if (!isItem) {
sprite = getSprite(spriteKey, hasShadow, yShadowOffset);
sprite = getSprite(spriteKey, hasShadow, yShadow);
tintSprite = getSprite(spriteKey);
} else {
sprite = getItemSprite(spriteKey);

View File

@ -1,4 +1,5 @@
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:
@ -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!",
lostAtSea,
theStrongStuff: theStrongStuffDialogue,
} 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
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
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

View File

@ -32,7 +32,8 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const charVarMap = new Map<integer, string>();
const delayMap = new Map<integer, integer>();
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;
while ((actionMatch = actionPattern.exec(text))) {
switch (actionMatch[1]) {
@ -45,6 +46,9 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
case "s":
soundMap.set(actionMatch.index, actionMatch[2]);
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);
}
@ -103,6 +107,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
const charVar = charVarMap.get(charIndex);
const charSound = soundMap.get(charIndex);
const charDelay = delayMap.get(charIndex);
const charFade = fadeMap.get(charIndex);
this.message.setText(text.slice(0, charIndex));
const advance = () => {
if (charVar) {
@ -134,6 +139,19 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler {
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 {
advance();
}