add encounter exp utility and small cleanups/refactors
This commit is contained in:
parent
cf43589260
commit
deb1e95e34
|
@ -2681,7 +2681,7 @@ export default class BattleScene extends SceneBase {
|
||||||
const tier = val[1];
|
const tier = val[1];
|
||||||
if (tier === MysteryEncounterTier.COMMON) {
|
if (tier === MysteryEncounterTier.COMMON) {
|
||||||
tierWeights[0] = tierWeights[0] - 6;
|
tierWeights[0] = tierWeights[0] - 6;
|
||||||
} else if (tier === MysteryEncounterTier.UNCOMMON) {
|
} else if (tier === MysteryEncounterTier.GREAT) {
|
||||||
tierWeights[1] = tierWeights[1] - 4;
|
tierWeights[1] = tierWeights[1] - 4;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2691,7 +2691,7 @@ export default class BattleScene extends SceneBase {
|
||||||
const commonThreshold = totalWeight - tierWeights[0];
|
const commonThreshold = totalWeight - tierWeights[0];
|
||||||
const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1];
|
const uncommonThreshold = totalWeight - tierWeights[0] - tierWeights[1];
|
||||||
const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2];
|
const rareThreshold = totalWeight - tierWeights[0] - tierWeights[1] - tierWeights[2];
|
||||||
let tier = tierValue > commonThreshold ? MysteryEncounterTier.COMMON : tierValue > uncommonThreshold ? MysteryEncounterTier.UNCOMMON : tierValue > rareThreshold ? MysteryEncounterTier.RARE : MysteryEncounterTier.SUPER_RARE;
|
let tier = tierValue > commonThreshold ? MysteryEncounterTier.COMMON : tierValue > uncommonThreshold ? MysteryEncounterTier.GREAT : tierValue > rareThreshold ? MysteryEncounterTier.ULTRA : MysteryEncounterTier.ROGUE;
|
||||||
|
|
||||||
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE)) {
|
if (!isNullOrUndefined(Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE)) {
|
||||||
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
|
tier = Overrides.MYSTERY_ENCOUNTER_TIER_OVERRIDE;
|
||||||
|
|
|
@ -239,7 +239,7 @@ export class MoneyRequirement extends EncounterSceneRequirement {
|
||||||
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
getDialogueToken(scene: BattleScene, pokemon?: PlayerPokemon): [string, string] {
|
||||||
const value = this?.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString();
|
const value = this?.scalingMultiplier > 0 ? scene.getWaveMoneyAmount(this.scalingMultiplier).toString() : this.requiredMoney.toString();
|
||||||
// Colors money text
|
// Colors money text
|
||||||
return ["money", "@ecCol[MONEY]{₽" + value + "}"];
|
return ["money", "@[MONEY]{₽" + value + "}"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,10 @@ export enum MysteryEncounterVariant {
|
||||||
|
|
||||||
export enum MysteryEncounterTier {
|
export enum MysteryEncounterTier {
|
||||||
COMMON,
|
COMMON,
|
||||||
UNCOMMON,
|
GREAT,
|
||||||
RARE,
|
ULTRA,
|
||||||
SUPER_RARE,
|
ROGUE,
|
||||||
ULTRA_RARE // Not currently used
|
MASTER // Not currently used
|
||||||
}
|
}
|
||||||
|
|
||||||
export default interface MysteryEncounter {
|
export default interface MysteryEncounter {
|
||||||
|
@ -44,6 +44,7 @@ export default interface MysteryEncounter {
|
||||||
hideBattleIntroMessage?: boolean;
|
hideBattleIntroMessage?: boolean;
|
||||||
hideIntroVisuals?: boolean;
|
hideIntroVisuals?: boolean;
|
||||||
catchAllowed?: boolean;
|
catchAllowed?: boolean;
|
||||||
|
doEncounterExp?: (scene: BattleScene) => boolean;
|
||||||
doEncounterRewards?: (scene: BattleScene) => boolean;
|
doEncounterRewards?: (scene: BattleScene) => boolean;
|
||||||
onInit?: (scene: BattleScene) => boolean;
|
onInit?: (scene: BattleScene) => boolean;
|
||||||
|
|
||||||
|
@ -347,6 +348,7 @@ export class MysteryEncounterBuilder implements Partial<MysteryEncounter> {
|
||||||
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
|
secondaryPokemonRequirements ?: EncounterPokemonRequirement[] = [];
|
||||||
excludePrimaryFromSupportRequirements?: boolean;
|
excludePrimaryFromSupportRequirements?: boolean;
|
||||||
dialogueTokens?: Map<string, [RegExp, string]>;
|
dialogueTokens?: Map<string, [RegExp, string]>;
|
||||||
|
doEncounterExp?: (scene: BattleScene) => boolean;
|
||||||
doEncounterRewards?: (scene: BattleScene) => boolean;
|
doEncounterRewards?: (scene: BattleScene) => boolean;
|
||||||
onInit?: (scene: BattleScene) => boolean;
|
onInit?: (scene: BattleScene) => boolean;
|
||||||
hideBattleIntroMessage?: boolean;
|
hideBattleIntroMessage?: boolean;
|
||||||
|
@ -448,8 +450,7 @@ export class MysteryEncounterBuilder implements Partial<MysteryEncounter> {
|
||||||
*
|
*
|
||||||
* NOTE: If rewards are dependent on options selected, runtime data, etc.,
|
* NOTE: If rewards are dependent on options selected, runtime data, etc.,
|
||||||
* It may be better to programmatically set doEncounterRewards elsewhere.
|
* It may be better to programmatically set doEncounterRewards elsewhere.
|
||||||
* For instance, doEncounterRewards could instead be set inside the onOptionPhase() callback function for a MysteryEncounterOption
|
* There is a helper function in mystery-encounter utils, setEncounterRewards(), which can be called programmatically to set rewards
|
||||||
* Check other existing mystery encounters for examples on how to use this
|
|
||||||
* @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter
|
* @param doEncounterRewards - synchronous callback function to perform during rewards phase of the encounter
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
|
@ -457,6 +458,20 @@ export class MysteryEncounterBuilder implements Partial<MysteryEncounter> {
|
||||||
return Object.assign(this, { doEncounterRewards: doEncounterRewards });
|
return Object.assign(this, { doEncounterRewards: doEncounterRewards });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can set custom encounter exp via this callback function
|
||||||
|
* If exp always deterministic for an encounter, this is a good way to set them
|
||||||
|
*
|
||||||
|
* NOTE: If rewards are dependent on options selected, runtime data, etc.,
|
||||||
|
* It may be better to programmatically set doEncounterExp elsewhere.
|
||||||
|
* There is a helper function in mystery-encounter utils, setEncounterExp(), which can be called programmatically to set rewards
|
||||||
|
* @param doEncounterExp - synchronous callback function to perform during rewards phase of the encounter
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
withExp(doEncounterExp: (scene: BattleScene) => boolean): this & Required<Pick<MysteryEncounter, "doEncounterExp">> {
|
||||||
|
return Object.assign(this, { doEncounterExp: doEncounterExp });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be used to perform init logic before intro visuals are shown and before the MysteryEncounterPhase begins
|
* Can be used to perform init logic before intro visuals are shown and before the MysteryEncounterPhase begins
|
||||||
* Useful for performing things like procedural generation of intro sprites, etc.
|
* Useful for performing things like procedural generation of intro sprites, etc.
|
||||||
|
|
|
@ -69,7 +69,7 @@ const excludedBosses = [
|
||||||
|
|
||||||
export const DarkDealEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
export const DarkDealEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
||||||
.withEncounterType(MysteryEncounterType.DARK_DEAL)
|
.withEncounterType(MysteryEncounterType.DARK_DEAL)
|
||||||
.withEncounterTier(MysteryEncounterTier.ULTRA_RARE)
|
.withEncounterTier(MysteryEncounterTier.ROGUE)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: "mad_scientist_m",
|
spriteKey: "mad_scientist_m",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import BattleScene from "../../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import {
|
import {
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle, setEncounterExp,
|
||||||
setCustomEncounterRewards,
|
setEncounterRewards,
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
@ -49,7 +49,8 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = new MysteryEncount
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
setEncounterExp(scene, scene.getParty().map(p => p.id), 300);
|
||||||
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
@ -69,7 +70,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = new MysteryEncount
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
@ -89,7 +90,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = new MysteryEncount
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
@ -113,7 +114,7 @@ export const DepartmentStoreSaleEncounter: MysteryEncounter = new MysteryEncount
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
EnemyPartyConfig,
|
EnemyPartyConfig,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle, queueEncounterMessage,
|
leaveEncounterWithoutBattle, queueEncounterMessage,
|
||||||
setCustomEncounterRewards,
|
setEncounterRewards,
|
||||||
showEncounterText
|
showEncounterText
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
|
@ -103,7 +103,7 @@ export const FightOrFlightEncounter: MysteryEncounter = new MysteryEncounterBuil
|
||||||
.withOptionPhase(async (scene: BattleScene) => {
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
// Pick battle
|
// Pick battle
|
||||||
const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
|
const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
|
||||||
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
|
await initBattleWithEnemyConfig(scene, scene.currentBattle.mysteryEncounter.enemyPartyConfigs[0]);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
@ -112,7 +112,7 @@ export const FightOrFlightEncounter: MysteryEncounter = new MysteryEncounterBuil
|
||||||
// Pick steal
|
// Pick steal
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
|
const item = scene.currentBattle.mysteryEncounter.misc as ModifierTypeOption;
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [item], fillRemaining: false});
|
||||||
|
|
||||||
// If player has a stealing move, they succeed automatically
|
// If player has a stealing move, they succeed automatically
|
||||||
const moveRequirement = new MoveRequirement(validMovesForSteal);
|
const moveRequirement = new MoveRequirement(validMovesForSteal);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import BattleScene from "../../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import {modifierTypes} from "#app/modifier/modifier-type";
|
import {modifierTypes} from "#app/modifier/modifier-type";
|
||||||
import { EnemyPartyConfig, initBattleWithEnemyConfig, setCustomEncounterRewards } from "#app/data/mystery-encounters/mystery-encounter-utils";
|
import { EnemyPartyConfig, initBattleWithEnemyConfig, setEncounterRewards } from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "../mystery-encounter-option";
|
||||||
|
@ -17,7 +17,7 @@ import {PartyMemberStrength} from "#enums/party-member-strength";
|
||||||
|
|
||||||
export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
||||||
.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS)
|
.withEncounterType(MysteryEncounterType.MYSTERIOUS_CHALLENGERS)
|
||||||
.withEncounterTier(MysteryEncounterTier.UNCOMMON)
|
.withEncounterTier(MysteryEncounterTier.GREAT)
|
||||||
.withIntroSpriteConfigs([]) // These are set in onInit()
|
.withIntroSpriteConfigs([]) // These are set in onInit()
|
||||||
.withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
|
.withSceneRequirement(new WaveCountRequirement([10, 180])) // waves 10 to 180
|
||||||
.withOnInit((scene: BattleScene) => {
|
.withOnInit((scene: BattleScene) => {
|
||||||
|
@ -103,7 +103,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncou
|
||||||
// Spawn standard trainer battle with memory mushroom reward
|
// Spawn standard trainer battle with memory mushroom reward
|
||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[0];
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.TM_COMMON, modifierTypes.TM_GREAT, modifierTypes.MEMORY_MUSHROOM], fillRemaining: true });
|
||||||
|
|
||||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||||
let ret;
|
let ret;
|
||||||
|
@ -119,7 +119,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncou
|
||||||
// Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
|
// Spawn hard fight with ULTRA/GREAT reward (can improve with luck)
|
||||||
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
const config: EnemyPartyConfig = encounter.enemyPartyConfigs[1];
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true });
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.GREAT, ModifierTier.GREAT], fillRemaining: true });
|
||||||
|
|
||||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||||
let ret;
|
let ret;
|
||||||
|
@ -138,7 +138,7 @@ export const MysteriousChallengersEncounter: MysteryEncounter = new MysteryEncou
|
||||||
// To avoid player level snowballing from picking this option
|
// To avoid player level snowballing from picking this option
|
||||||
encounter.expMultiplier = 0.9;
|
encounter.expMultiplier = 0.9;
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ULTRA, ModifierTier.GREAT], fillRemaining: true });
|
||||||
|
|
||||||
// Seed offsets to remove possibility of different trainers having exact same teams
|
// Seed offsets to remove possibility of different trainers having exact same teams
|
||||||
let ret;
|
let ret;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
koPlayerPokemon,
|
koPlayerPokemon,
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
queueEncounterMessage,
|
queueEncounterMessage,
|
||||||
setCustomEncounterRewards,
|
setEncounterRewards,
|
||||||
showEncounterText
|
showEncounterText
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
|
@ -42,25 +42,25 @@ export const MysteriousChestEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
const roll = randSeedInt(100);
|
const roll = randSeedInt(100);
|
||||||
if (roll > 60) {
|
if (roll > 60) {
|
||||||
// Choose between 2 COMMON / 2 GREAT tier items (40%)
|
// Choose between 2 COMMON / 2 GREAT tier items (40%)
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.GREAT]});
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.GREAT]});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_normal_result");
|
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_normal_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
} else if (roll > 40) {
|
} else if (roll > 40) {
|
||||||
// Choose between 3 ULTRA tier items (20%)
|
// Choose between 3 ULTRA tier items (20%)
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA]});
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ULTRA, ModifierTier.ULTRA, ModifierTier.ULTRA]});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_good_result");
|
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_good_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
} else if (roll > 36) {
|
} else if (roll > 36) {
|
||||||
// Choose between 2 ROGUE tier items (4%)
|
// Choose between 2 ROGUE tier items (4%)
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE]});
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.ROGUE, ModifierTier.ROGUE]});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_great_result");
|
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_great_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
} else if (roll > 35) {
|
} else if (roll > 35) {
|
||||||
// Choose 1 MASTER tier item (1%)
|
// Choose 1 MASTER tier item (1%)
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER]});
|
setEncounterRewards(scene, { guaranteedModifierTiers: [ModifierTier.MASTER]});
|
||||||
// Display result message then proceed to rewards
|
// Display result message then proceed to rewards
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_amazing_result");
|
queueEncounterMessage(scene, "mysteryEncounter:mysterious_chest_option_1_amazing_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
|
|
|
@ -7,7 +7,12 @@ import {Status, StatusEffect} from "../status-effect";
|
||||||
import {TrainerConfig, trainerConfigs, TrainerSlot} from "../trainer-config";
|
import {TrainerConfig, trainerConfigs, TrainerSlot} from "../trainer-config";
|
||||||
import Pokemon, {FieldPosition, PlayerPokemon} from "#app/field/pokemon";
|
import Pokemon, {FieldPosition, PlayerPokemon} from "#app/field/pokemon";
|
||||||
import Trainer, {TrainerVariant} from "../../field/trainer";
|
import Trainer, {TrainerVariant} from "../../field/trainer";
|
||||||
import {PokemonExpBoosterModifier} from "#app/modifier/modifier";
|
import {
|
||||||
|
ExpBalanceModifier,
|
||||||
|
ExpShareModifier,
|
||||||
|
MultipleParticipantExpBonusModifier,
|
||||||
|
PokemonExpBoosterModifier
|
||||||
|
} from "#app/modifier/modifier";
|
||||||
import {
|
import {
|
||||||
CustomModifierSettings,
|
CustomModifierSettings,
|
||||||
getModifierPoolForType,
|
getModifierPoolForType,
|
||||||
|
@ -19,7 +24,14 @@ import {
|
||||||
PokemonHeldItemModifierType,
|
PokemonHeldItemModifierType,
|
||||||
regenerateModifierPoolThresholds
|
regenerateModifierPoolThresholds
|
||||||
} from "#app/modifier/modifier-type";
|
} from "#app/modifier/modifier-type";
|
||||||
import {BattleEndPhase, EggLapsePhase, ModifierRewardPhase, TrainerVictoryPhase} from "#app/phases";
|
import {
|
||||||
|
BattleEndPhase,
|
||||||
|
EggLapsePhase,
|
||||||
|
ExpPhase,
|
||||||
|
ModifierRewardPhase,
|
||||||
|
ShowPartyExpBarPhase,
|
||||||
|
TrainerVictoryPhase
|
||||||
|
} from "#app/phases";
|
||||||
import {MysteryEncounterBattlePhase, MysteryEncounterRewardsPhase} from "#app/phases/mystery-encounter-phase";
|
import {MysteryEncounterBattlePhase, MysteryEncounterRewardsPhase} from "#app/phases/mystery-encounter-phase";
|
||||||
import * as Utils from "../../utils";
|
import * as Utils from "../../utils";
|
||||||
import {isNullOrUndefined} from "#app/utils";
|
import {isNullOrUndefined} from "#app/utils";
|
||||||
|
@ -35,7 +47,9 @@ import {Mode} from "#app/ui/ui";
|
||||||
import {PartyOption, PartyUiMode} from "#app/ui/party-ui-handler";
|
import {PartyOption, PartyUiMode} from "#app/ui/party-ui-handler";
|
||||||
import {OptionSelectConfig, OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
|
import {OptionSelectConfig, OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import {WIGHT_INCREMENT_ON_SPAWN_MISS} from "#app/data/mystery-encounters/mystery-encounters";
|
import {WIGHT_INCREMENT_ON_SPAWN_MISS} from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
import {getBBCodeFrag, TextStyle} from "#app/ui/text";
|
import {getTextWithColors, TextStyle} from "#app/ui/text";
|
||||||
|
import * as Overrides from "#app/overrides";
|
||||||
|
import {UiTheme} from "#enums/ui-theme";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -167,17 +181,29 @@ export function koPlayerPokemon(pokemon: PlayerPokemon) {
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTextWithEncounterDialogueTokensAndColor(scene: BattleScene, textKey: TemplateStringsArray | `mysteryEncounter:${string}`, primaryStyle: TextStyle = TextStyle.MESSAGE): string {
|
export function getEncounterText(scene: BattleScene, textKey: TemplateStringsArray | `mysteryEncounter:${string}`, primaryStyle?: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string {
|
||||||
|
if (isNullOrUndefined(textKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let textString: string = getTextWithDialogueTokens(scene, textKey);
|
||||||
|
|
||||||
|
// Can only color the text if a Primary Style is defined
|
||||||
|
// primaryStyle is applied to all text that does not have its own specified style
|
||||||
|
if (primaryStyle) {
|
||||||
|
textString = getTextWithColors(textString, primaryStyle, uiTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
return textString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextWithDialogueTokens(scene: BattleScene, textKey: TemplateStringsArray | `mysteryEncounter:${string}`): string {
|
||||||
if (isNullOrUndefined(textKey)) {
|
if (isNullOrUndefined(textKey)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let textString: string = i18next.t(textKey);
|
let textString: string = i18next.t(textKey);
|
||||||
|
|
||||||
// Apply primary styling before anything else, if it exists
|
|
||||||
textString = getBBCodeFrag(textString, primaryStyle) + "[/color][/shadow]";
|
|
||||||
const primaryStyleString = [...textString.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0];
|
|
||||||
|
|
||||||
// Apply dialogue tokens
|
// Apply dialogue tokens
|
||||||
const dialogueTokens = scene.currentBattle?.mysteryEncounter?.dialogueTokens;
|
const dialogueTokens = scene.currentBattle?.mysteryEncounter?.dialogueTokens;
|
||||||
if (dialogueTokens) {
|
if (dialogueTokens) {
|
||||||
|
@ -186,16 +212,6 @@ export function getTextWithEncounterDialogueTokensAndColor(scene: BattleScene, t
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set custom colors
|
|
||||||
// Looks for any pattern like this: @ecCol[SUMMARY_BLUE]{my text to color}
|
|
||||||
// Resulting in: "my text to color" string with TextStyle.SUMMARY_BLUE
|
|
||||||
textString = textString.replace(/@ecCol\[([^{]*)\]{([^}]*)}/gi, (substring, textStyle: string, textToColor: string) => {
|
|
||||||
return "[/color][/shadow]" + getBBCodeFrag(textToColor, TextStyle[textStyle]) + "[/color][/shadow]" + primaryStyleString;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove extra style block at the end
|
|
||||||
textString = textString.replace(/\[color=[^\[]*\]\[shadow=[^\[]*\]\[\/color\]\[\/shadow\]/gi, "");
|
|
||||||
|
|
||||||
return textString;
|
return textString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +221,7 @@ export function getTextWithEncounterDialogueTokensAndColor(scene: BattleScene, t
|
||||||
* @param contentKey
|
* @param contentKey
|
||||||
*/
|
*/
|
||||||
export function queueEncounterMessage(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): void {
|
export function queueEncounterMessage(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): void {
|
||||||
const text: string = getTextWithEncounterDialogueTokensAndColor(scene, contentKey, TextStyle.MESSAGE);
|
const text: string = getEncounterText(scene, contentKey);
|
||||||
scene.queueMessage(text, null, true);
|
scene.queueMessage(text, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +232,7 @@ export function queueEncounterMessage(scene: BattleScene, contentKey: TemplateSt
|
||||||
*/
|
*/
|
||||||
export function showEncounterText(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): Promise<void> {
|
export function showEncounterText(scene: BattleScene, contentKey: TemplateStringsArray | `mysteryEncounter:${string}`): Promise<void> {
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
const text: string = getTextWithEncounterDialogueTokensAndColor(scene, contentKey, TextStyle.MESSAGE);
|
const text: string = getEncounterText(scene, contentKey);
|
||||||
scene.ui.showText(text, null, () => resolve(), 0, true);
|
scene.ui.showText(text, null, () => resolve(), 0, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -229,8 +245,8 @@ export function showEncounterText(scene: BattleScene, contentKey: TemplateString
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
export function showEncounterDialogue(scene: BattleScene, textContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, speakerContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, callback?: Function) {
|
export function showEncounterDialogue(scene: BattleScene, textContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, speakerContentKey: TemplateStringsArray | `mysteryEncounter:${string}`, callback?: Function) {
|
||||||
const text: string = getTextWithEncounterDialogueTokensAndColor(scene, textContentKey, TextStyle.MESSAGE);
|
const text: string = getEncounterText(scene, textContentKey);
|
||||||
const speaker: string = getTextWithEncounterDialogueTokensAndColor(scene, speakerContentKey);
|
const speaker: string = getEncounterText(scene, speakerContentKey);
|
||||||
scene.ui.showDialogue(text, speaker, null, callback, 0, 0);
|
scene.ui.showDialogue(text, speaker, null, callback, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +262,7 @@ export class EnemyPokemonConfig {
|
||||||
tags?: BattlerTagType[];
|
tags?: BattlerTagType[];
|
||||||
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
mysteryEncounterBattleEffects?: (pokemon: Pokemon) => void;
|
||||||
status?: StatusEffect;
|
status?: StatusEffect;
|
||||||
|
passive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EnemyPartyConfig {
|
export class EnemyPartyConfig {
|
||||||
|
@ -341,6 +358,11 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||||
|
|
||||||
const enemyPokemon = scene.getEnemyParty()[e];
|
const enemyPokemon = scene.getEnemyParty()[e];
|
||||||
|
|
||||||
|
// Make sure basic data is clean
|
||||||
|
enemyPokemon.hp = enemyPokemon.getMaxHp();
|
||||||
|
enemyPokemon.status = null;
|
||||||
|
enemyPokemon.passive = false;
|
||||||
|
|
||||||
if (e < (doubleBattle ? 2 : 1)) {
|
if (e < (doubleBattle ? 2 : 1)) {
|
||||||
enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]);
|
enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]);
|
||||||
enemyPokemon.resetSummonData();
|
enemyPokemon.resetSummonData();
|
||||||
|
@ -353,7 +375,7 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||||
if (e < partyConfig?.pokemonConfigs?.length) {
|
if (e < partyConfig?.pokemonConfigs?.length) {
|
||||||
const config = partyConfig?.pokemonConfigs?.[e];
|
const config = partyConfig?.pokemonConfigs?.[e];
|
||||||
|
|
||||||
// Generate new id in case using data source
|
// Generate new id, reset status and HP in case using data source
|
||||||
if (config.dataSource) {
|
if (config.dataSource) {
|
||||||
enemyPokemon.id = Utils.randSeedInt(4294967296);
|
enemyPokemon.id = Utils.randSeedInt(4294967296);
|
||||||
}
|
}
|
||||||
|
@ -372,6 +394,11 @@ export async function initBattleWithEnemyConfig(scene: BattleScene, partyConfig:
|
||||||
enemyPokemon.setBoss(true, segments);
|
enemyPokemon.setBoss(true, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set Passive
|
||||||
|
if (partyConfig.pokemonConfigs[e].passive) {
|
||||||
|
enemyPokemon.passive = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Set Status
|
// Set Status
|
||||||
if (partyConfig.pokemonConfigs[e].status) {
|
if (partyConfig.pokemonConfigs[e].status) {
|
||||||
// Default to cureturn 3 for sleep
|
// Default to cureturn 3 for sleep
|
||||||
|
@ -462,40 +489,6 @@ export function generateModifierType(scene: BattleScene, modifier: () => Modifie
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Will initialize reward phases to follow the mystery encounter
|
|
||||||
* Can have shop displayed or skipped
|
|
||||||
* @param scene - Battle Scene
|
|
||||||
* @param customShopRewards - adds a shop phase with the specified rewards / reward tiers
|
|
||||||
* @param nonShopRewards - will add a non-shop reward phase for each specified item/modifier (can happen in addition to a shop)
|
|
||||||
* @param preRewardsCallback - can execute an arbitrary callback before the new phases if necessary (useful for updating items/party/injecting new phases before MysteryEncounterRewardsPhase)
|
|
||||||
*/
|
|
||||||
export function setCustomEncounterRewards(scene: BattleScene, customShopRewards?: CustomModifierSettings, nonShopRewards?: ModifierTypeFunc[], preRewardsCallback?: Function) {
|
|
||||||
scene.currentBattle.mysteryEncounter.doEncounterRewards = (scene: BattleScene) => {
|
|
||||||
if (preRewardsCallback) {
|
|
||||||
preRewardsCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customShopRewards) {
|
|
||||||
scene.unshiftPhase(new SelectModifierPhase(scene, 0, null, customShopRewards));
|
|
||||||
} else {
|
|
||||||
scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonShopRewards?.length > 0) {
|
|
||||||
nonShopRewards.forEach((reward) => {
|
|
||||||
scene.unshiftPhase(new ModifierRewardPhase(scene, reward));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
while (!isNullOrUndefined(scene.findPhase(p => p instanceof ModifierRewardPhase))) {
|
|
||||||
scene.tryRemovePhase(p => p instanceof ModifierRewardPhase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param scene
|
* @param scene
|
||||||
|
@ -557,7 +550,7 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
||||||
if (!textPromptKey) {
|
if (!textPromptKey) {
|
||||||
displayOptions();
|
displayOptions();
|
||||||
} else {
|
} else {
|
||||||
const secondOptionSelectPrompt = getTextWithEncounterDialogueTokensAndColor(scene, textPromptKey, TextStyle.MESSAGE);
|
const secondOptionSelectPrompt = getEncounterText(scene, textPromptKey, TextStyle.MESSAGE);
|
||||||
scene.ui.showText(secondOptionSelectPrompt, null, displayOptions, null, true);
|
scene.ui.showText(secondOptionSelectPrompt, null, displayOptions, null, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -575,49 +568,140 @@ export function selectPokemonForOption(scene: BattleScene, onPokemonSelected: (p
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will initialize exp phases to follow the mystery encounter (in addition to any combat or other exp earned)
|
* Will initialize reward phases to follow the mystery encounter
|
||||||
* Exp earned will be a simple function that linearly scales with wave index, that can be increased or decreased by the expMultiplier
|
* Can have shop displayed or skipped
|
||||||
* Exp Share will have no effect (so no accounting for what mon is "on the field")
|
|
||||||
* Exp Balance will still function as normal
|
|
||||||
* @param scene - Battle Scene
|
* @param scene - Battle Scene
|
||||||
* @param expMultiplier - default is 100, can be increased or decreased as desired
|
* @param customShopRewards - adds a shop phase with the specified rewards / reward tiers
|
||||||
|
* @param nonShopRewards - will add a non-shop reward phase for each specified item/modifier (can happen in addition to a shop)
|
||||||
|
* @param preRewardsCallback - can execute an arbitrary callback before the new phases if necessary (useful for updating items/party/injecting new phases before MysteryEncounterRewardsPhase)
|
||||||
*/
|
*/
|
||||||
export function setEncounterExp(scene: BattleScene, expMultiplier: number = 100) {
|
export function setEncounterRewards(scene: BattleScene, customShopRewards?: CustomModifierSettings, nonShopRewards?: ModifierTypeFunc[], preRewardsCallback?: Function) {
|
||||||
//const expBalanceModifier = scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
|
scene.currentBattle.mysteryEncounter.doEncounterRewards = (scene: BattleScene) => {
|
||||||
const expVal = scene.currentBattle.waveIndex * expMultiplier;
|
if (preRewardsCallback) {
|
||||||
const pokemonExp = new Utils.NumberHolder(expVal);
|
preRewardsCallback();
|
||||||
const partyMemberExp = [];
|
}
|
||||||
|
|
||||||
const party = scene.getParty();
|
if (customShopRewards) {
|
||||||
party.forEach(pokemon => {
|
scene.unshiftPhase(new SelectModifierPhase(scene, 0, null, customShopRewards));
|
||||||
scene.applyModifiers(PokemonExpBoosterModifier, true, pokemon, pokemonExp);
|
} else {
|
||||||
partyMemberExp.push(Math.floor(pokemonExp.value));
|
scene.tryRemovePhase(p => p instanceof SelectModifierPhase);
|
||||||
});
|
}
|
||||||
|
|
||||||
// TODO
|
if (nonShopRewards?.length > 0) {
|
||||||
//if (expBalanceModifier) {
|
nonShopRewards.forEach((reward) => {
|
||||||
// let totalLevel = 0;
|
scene.unshiftPhase(new ModifierRewardPhase(scene, reward));
|
||||||
// let totalExp = 0;
|
});
|
||||||
// expPartyMembers.forEach((expPartyMember, epm) => {
|
} else {
|
||||||
// totalExp += partyMemberExp[epm];
|
while (!isNullOrUndefined(scene.findPhase(p => p instanceof ModifierRewardPhase))) {
|
||||||
// totalLevel += expPartyMember.level;
|
scene.tryRemovePhase(p => p instanceof ModifierRewardPhase);
|
||||||
// });
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// const medianLevel = Math.floor(totalLevel / expPartyMembers.length);
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// const recipientExpPartyMemberIndexes = [];
|
/**
|
||||||
// expPartyMembers.forEach((expPartyMember, epm) => {
|
* Will initialize exp phases into the phase queue (these are in addition to any combat or other exp earned)
|
||||||
// if (expPartyMember.level <= medianLevel) {
|
* Exp Share and Exp Balance will still function as normal
|
||||||
// recipientExpPartyMemberIndexes.push(epm);
|
* @param scene - Battle Scene
|
||||||
// }
|
* @param participantIds - ids of party pokemon that get full exp value. Other party members will receive Exp Share amounts
|
||||||
// });
|
* @param baseExpValue - gives exp equivalent to a pokemon of the wave index's level.
|
||||||
|
* Guidelines:
|
||||||
|
* 36 - Sunkern (lowest in game)
|
||||||
|
* 62-64 - regional starter base evos
|
||||||
|
* 100 - Scyther
|
||||||
|
* 170 - Spiritomb
|
||||||
|
* 250 - Gengar
|
||||||
|
* 290 - trio legendaries
|
||||||
|
* 340 - box legendaries
|
||||||
|
* 608 - Blissey (highest in game)
|
||||||
|
* @param useWaveIndex - set to false when directly passing the the full exp value instead of baseExpValue
|
||||||
|
*/
|
||||||
|
export function setEncounterExp(scene: BattleScene, participantIds: integer[], baseExpValue: number, useWaveIndex: boolean = true) {
|
||||||
|
scene.currentBattle.mysteryEncounter.doEncounterExp = (scene: BattleScene) => {
|
||||||
|
const party = scene.getParty();
|
||||||
|
const expShareModifier = scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
|
||||||
|
const expBalanceModifier = scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
|
||||||
|
const multipleParticipantExpBonusModifier = scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier;
|
||||||
|
const nonFaintedPartyMembers = party.filter(p => p.hp);
|
||||||
|
const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < scene.getMaxExpLevel());
|
||||||
|
const partyMemberExp = [];
|
||||||
|
let expValue = baseExpValue * (useWaveIndex ? scene.currentBattle.waveIndex : 1);
|
||||||
|
|
||||||
// const splitExp = Math.floor(totalExp / recipientExpPartyMemberIndexes.length);
|
if (participantIds?.length > 0) {
|
||||||
|
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) {
|
||||||
|
expValue = Math.floor(expValue * 1.5);
|
||||||
|
}
|
||||||
|
for (const partyMember of nonFaintedPartyMembers) {
|
||||||
|
const pId = partyMember.id;
|
||||||
|
const participated = participantIds.includes(pId);
|
||||||
|
if (participated) {
|
||||||
|
partyMember.addFriendship(2);
|
||||||
|
}
|
||||||
|
if (!expPartyMembers.includes(partyMember)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!participated && !expShareModifier) {
|
||||||
|
partyMemberExp.push(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let expMultiplier = 0;
|
||||||
|
if (participated) {
|
||||||
|
expMultiplier += (1 / participantIds.length);
|
||||||
|
if (participantIds.length > 1 && multipleParticipantExpBonusModifier) {
|
||||||
|
expMultiplier += multipleParticipantExpBonusModifier.getStackCount() * 0.2;
|
||||||
|
}
|
||||||
|
} else if (expShareModifier) {
|
||||||
|
expMultiplier += (expShareModifier.getStackCount() * 0.2) / participantIds.length;
|
||||||
|
}
|
||||||
|
if (partyMember.pokerus) {
|
||||||
|
expMultiplier *= 1.5;
|
||||||
|
}
|
||||||
|
if (Overrides.XP_MULTIPLIER_OVERRIDE !== null) {
|
||||||
|
expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE;
|
||||||
|
}
|
||||||
|
const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier);
|
||||||
|
scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp);
|
||||||
|
partyMemberExp.push(Math.floor(pokemonExp.value));
|
||||||
|
}
|
||||||
|
|
||||||
// expPartyMembers.forEach((_partyMember, pm) => {
|
if (expBalanceModifier) {
|
||||||
// partyMemberExp[pm] = Phaser.Math.Linear(partyMemberExp[pm], recipientExpPartyMemberIndexes.indexOf(pm) > -1 ? splitExp : 0, 0.2 * expBalanceModifier.getStackCount());
|
let totalLevel = 0;
|
||||||
// });
|
let totalExp = 0;
|
||||||
//}
|
expPartyMembers.forEach((expPartyMember, epm) => {
|
||||||
|
totalExp += partyMemberExp[epm];
|
||||||
|
totalLevel += expPartyMember.level;
|
||||||
|
});
|
||||||
|
|
||||||
|
const medianLevel = Math.floor(totalLevel / expPartyMembers.length);
|
||||||
|
|
||||||
|
const recipientExpPartyMemberIndexes = [];
|
||||||
|
expPartyMembers.forEach((expPartyMember, epm) => {
|
||||||
|
if (expPartyMember.level <= medianLevel) {
|
||||||
|
recipientExpPartyMemberIndexes.push(epm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const splitExp = Math.floor(totalExp / recipientExpPartyMemberIndexes.length);
|
||||||
|
|
||||||
|
expPartyMembers.forEach((_partyMember, pm) => {
|
||||||
|
partyMemberExp[pm] = Phaser.Math.Linear(partyMemberExp[pm], recipientExpPartyMemberIndexes.indexOf(pm) > -1 ? splitExp : 0, 0.2 * expBalanceModifier.getStackCount());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let pm = 0; pm < expPartyMembers.length; pm++) {
|
||||||
|
const exp = partyMemberExp[pm];
|
||||||
|
|
||||||
|
if (exp) {
|
||||||
|
const partyMemberIndex = party.indexOf(expPartyMembers[pm]);
|
||||||
|
scene.unshiftPhase(expPartyMembers[pm].isOnField() ? new ExpPhase(scene, partyMemberIndex, exp) : new ShowPartyExpBarPhase(scene, partyMemberIndex, exp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
leaveEncounterWithoutBattle,
|
leaveEncounterWithoutBattle,
|
||||||
queueEncounterMessage,
|
queueEncounterMessage,
|
||||||
selectPokemonForOption,
|
selectPokemonForOption,
|
||||||
setCustomEncounterRewards,
|
setEncounterRewards,
|
||||||
updatePlayerMoney,
|
updatePlayerMoney,
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
|
@ -134,7 +134,7 @@ export const ShadyVitaminDealerEncounter: MysteryEncounter = new MysteryEncounte
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: modifiers, fillRemaining: false});
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
.build())
|
.build())
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
EnemyPokemonConfig, generateModifierType,
|
EnemyPokemonConfig, generateModifierType,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
leaveEncounterWithoutBattle, queueEncounterMessage,
|
leaveEncounterWithoutBattle, queueEncounterMessage,
|
||||||
setCustomEncounterRewards
|
setEncounterRewards
|
||||||
} from "./mystery-encounter-utils";
|
} from "./mystery-encounter-utils";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
import * as Utils from "../../utils";
|
import * as Utils from "../../utils";
|
||||||
|
@ -23,7 +23,7 @@ import { BerryType } from "#enums/berry-type";
|
||||||
|
|
||||||
export const SleepingSnorlaxEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
export const SleepingSnorlaxEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
||||||
.withEncounterType(MysteryEncounterType.SLEEPING_SNORLAX)
|
.withEncounterType(MysteryEncounterType.SLEEPING_SNORLAX)
|
||||||
.withEncounterTier(MysteryEncounterTier.RARE)
|
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: Species.SNORLAX.toString(),
|
spriteKey: Species.SNORLAX.toString(),
|
||||||
|
@ -78,7 +78,7 @@ export const SleepingSnorlaxEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
// const sitrus = (modifierTypes.BERRY?.() as ModifierTypeGenerator).generateType(scene.getParty(), [BerryType.SITRUS]);
|
// const sitrus = (modifierTypes.BERRY?.() as ModifierTypeGenerator).generateType(scene.getParty(), [BerryType.SITRUS]);
|
||||||
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
|
const sitrus = generateModifierType(scene, modifierTypes.BERRY, [BerryType.SITRUS]);
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeOptions: [new ModifierTypeOption(sitrus, 0)], fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeOptions: [new ModifierTypeOption(sitrus, 0)], fillRemaining: false});
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_bad_result");
|
queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_2_bad_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,7 +101,7 @@ export const SleepingSnorlaxEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
.withPrimaryPokemonRequirement(new MoveRequirement([Moves.PLUCK, Moves.COVET, Moves.KNOCK_OFF, Moves.THIEF, Moves.TRICK, Moves.SWITCHEROO]))
|
.withPrimaryPokemonRequirement(new MoveRequirement([Moves.PLUCK, Moves.COVET, Moves.KNOCK_OFF, Moves.THIEF, Moves.TRICK, Moves.SWITCHEROO]))
|
||||||
.withOptionPhase(async (scene: BattleScene) => {
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
// Leave encounter with no rewards or exp
|
// Leave encounter with no rewards or exp
|
||||||
setCustomEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false});
|
setEncounterRewards(scene, { guaranteedModifierTypeFuncs: [modifierTypes.LEFTOVERS], fillRemaining: false});
|
||||||
queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_3_good_result");
|
queueEncounterMessage(scene, "mysteryEncounter:sleeping_snorlax_option_3_good_result");
|
||||||
leaveEncounterWithoutBattle(scene);
|
leaveEncounterWithoutBattle(scene);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import BattleScene from "../../battle-scene";
|
import BattleScene from "../../battle-scene";
|
||||||
import {
|
import {
|
||||||
EnemyPartyConfig,
|
EnemyPartyConfig,
|
||||||
getTextWithEncounterDialogueTokensAndColor,
|
getEncounterText,
|
||||||
initBattleWithEnemyConfig,
|
initBattleWithEnemyConfig,
|
||||||
selectPokemonForOption,
|
selectPokemonForOption,
|
||||||
setCustomEncounterRewards
|
setEncounterRewards
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import {MysteryEncounterType} from "#enums/mystery-encounter-type";
|
import {MysteryEncounterType} from "#enums/mystery-encounter-type";
|
||||||
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
import MysteryEncounter, {MysteryEncounterBuilder, MysteryEncounterTier} from "../mystery-encounter";
|
||||||
|
@ -26,7 +26,7 @@ import {pokemonInfo} from "#app/locales/en/pokemon-info";
|
||||||
|
|
||||||
export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBuilder()
|
||||||
.withEncounterType(MysteryEncounterType.TRAINING_SESSION)
|
.withEncounterType(MysteryEncounterType.TRAINING_SESSION)
|
||||||
.withEncounterTier(MysteryEncounterTier.RARE)
|
.withEncounterTier(MysteryEncounterTier.ULTRA)
|
||||||
.withIntroSpriteConfigs([
|
.withIntroSpriteConfigs([
|
||||||
{
|
{
|
||||||
spriteKey: "training_gear",
|
spriteKey: "training_gear",
|
||||||
|
@ -128,10 +128,10 @@ export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
scene.addModifier(mod, true, false, false, true);
|
scene.addModifier(mod, true, false, false, true);
|
||||||
}
|
}
|
||||||
scene.updateModifiers(true);
|
scene.updateModifiers(true);
|
||||||
scene.queueMessage(getTextWithEncounterDialogueTokensAndColor(scene, "mysteryEncounter:training_session_battle_finished_1"), null, true);
|
scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_1"), null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
||||||
|
|
||||||
return initBattleWithEnemyConfig(scene, config);
|
return initBattleWithEnemyConfig(scene, config);
|
||||||
})
|
})
|
||||||
|
@ -174,7 +174,7 @@ export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
scene.removePokemonFromPlayerParty(playerPokemon, false);
|
scene.removePokemonFromPlayerParty(playerPokemon, false);
|
||||||
|
|
||||||
const onBeforeRewardsPhase = () => {
|
const onBeforeRewardsPhase = () => {
|
||||||
scene.queueMessage(getTextWithEncounterDialogueTokensAndColor(scene, "mysteryEncounter:training_session_battle_finished_2"), null, true);
|
scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_2"), null, true);
|
||||||
// Add the pokemon back to party with Nature change
|
// Add the pokemon back to party with Nature change
|
||||||
playerPokemon.setNature(encounter.misc.chosenNature);
|
playerPokemon.setNature(encounter.misc.chosenNature);
|
||||||
scene.gameData.setPokemonCaught(playerPokemon, false);
|
scene.gameData.setPokemonCaught(playerPokemon, false);
|
||||||
|
@ -187,7 +187,7 @@ export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
scene.updateModifiers(true);
|
scene.updateModifiers(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
||||||
|
|
||||||
return initBattleWithEnemyConfig(scene, config);
|
return initBattleWithEnemyConfig(scene, config);
|
||||||
})
|
})
|
||||||
|
@ -237,7 +237,7 @@ export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
scene.removePokemonFromPlayerParty(playerPokemon, false);
|
scene.removePokemonFromPlayerParty(playerPokemon, false);
|
||||||
|
|
||||||
const onBeforeRewardsPhase = () => {
|
const onBeforeRewardsPhase = () => {
|
||||||
scene.queueMessage(getTextWithEncounterDialogueTokensAndColor(scene, "mysteryEncounter:training_session_battle_finished_3"), null, true);
|
scene.queueMessage(getEncounterText(scene, "mysteryEncounter:training_session_battle_finished_3"), null, true);
|
||||||
// Add the pokemon back to party with ability change
|
// Add the pokemon back to party with ability change
|
||||||
const abilityIndex = encounter.misc.abilityIndex;
|
const abilityIndex = encounter.misc.abilityIndex;
|
||||||
if (!!playerPokemon.getFusionSpeciesForm()) {
|
if (!!playerPokemon.getFusionSpeciesForm()) {
|
||||||
|
@ -268,7 +268,7 @@ export const TrainingSessionEncounter: MysteryEncounter = new MysteryEncounterBu
|
||||||
scene.updateModifiers(true);
|
scene.updateModifiers(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
setCustomEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
setEncounterRewards(scene, { fillRemaining: true }, null, onBeforeRewardsPhase);
|
||||||
|
|
||||||
return initBattleWithEnemyConfig(scene, config);
|
return initBattleWithEnemyConfig(scene, config);
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,10 +7,10 @@ import {SimpleTranslationEntries} from "#app/interfaces/locales";
|
||||||
*
|
*
|
||||||
* '@ec{<token>}' will auto-inject the matching token value for the specified Encounter
|
* '@ec{<token>}' will auto-inject the matching token value for the specified Encounter
|
||||||
*
|
*
|
||||||
* '@ecCol[<TextStyle>]{<text>}' will auto-color the given text to a specified TextStyle (e.g. TextStyle.SUMMARY_GREEN)
|
* '@[<TextStyle>]{<text>}' will auto-color the given text to a specified TextStyle (e.g. TextStyle.SUMMARY_GREEN)
|
||||||
*
|
*
|
||||||
* Any '(+)' or '(-)' type of tooltip will auto-color to green/blue respectively. THIS ONLY OCCURS FOR OPTION TOOLTIPS, NOWHERE ELSE
|
* Any '(+)' or '(-)' type of tooltip will auto-color to green/blue respectively. THIS ONLY OCCURS FOR OPTION TOOLTIPS, NOWHERE ELSE
|
||||||
* Other types of '(...)' tooltips will have to specify the text color manually by using '@ecCol[SUMMARY_GREEN]{<text>}' pattern
|
* Other types of '(...)' tooltips will have to specify the text color manually by using '@[SUMMARY_GREEN]{<text>}' pattern
|
||||||
*/
|
*/
|
||||||
export const mysteryEncounter: SimpleTranslationEntries = {
|
export const mysteryEncounter: SimpleTranslationEntries = {
|
||||||
// DO NOT REMOVE
|
// DO NOT REMOVE
|
||||||
|
@ -22,7 +22,7 @@ export const mysteryEncounter: SimpleTranslationEntries = {
|
||||||
"mysterious_chest_description": "A beautifully ornamented chest stands on the ground. There must be something good inside... right?",
|
"mysterious_chest_description": "A beautifully ornamented chest stands on the ground. There must be something good inside... right?",
|
||||||
"mysterious_chest_query": "Will you open it?",
|
"mysterious_chest_query": "Will you open it?",
|
||||||
"mysterious_chest_option_1_label": "Open it",
|
"mysterious_chest_option_1_label": "Open it",
|
||||||
"mysterious_chest_option_1_tooltip": "@ecCol[SUMMARY_BLUE]{(35%) Something terrible}\n@ecCol[SUMMARY_GREEN]{(40%) Okay Rewards}\n@ecCol[SUMMARY_GREEN]{(20%) Good Rewards}\n@ecCol[SUMMARY_GREEN]{(4%) Great Rewards}\n@ecCol[SUMMARY_GREEN]{(1%) Amazing Rewards}",
|
"mysterious_chest_option_1_tooltip": "@[SUMMARY_BLUE]{(35%) Something terrible}\n@[SUMMARY_GREEN]{(40%) Okay Rewards}\n@[SUMMARY_GREEN]{(20%) Good Rewards}\n@[SUMMARY_GREEN]{(4%) Great Rewards}\n@[SUMMARY_GREEN]{(1%) Amazing Rewards}",
|
||||||
"mysterious_chest_option_2_label": "It's too risky, leave",
|
"mysterious_chest_option_2_label": "It's too risky, leave",
|
||||||
"mysterious_chest_option_2_tooltip": "(-) No Rewards",
|
"mysterious_chest_option_2_tooltip": "(-) No Rewards",
|
||||||
"mysterious_chest_option_1_selected_message": "You open the chest to find...",
|
"mysterious_chest_option_1_selected_message": "You open the chest to find...",
|
||||||
|
@ -41,8 +41,8 @@ export const mysteryEncounter: SimpleTranslationEntries = {
|
||||||
"fight_or_flight_option_1_label": "Battle the Pokémon",
|
"fight_or_flight_option_1_label": "Battle the Pokémon",
|
||||||
"fight_or_flight_option_1_tooltip": "(-) Hard Battle\n(+) New Item",
|
"fight_or_flight_option_1_tooltip": "(-) Hard Battle\n(+) New Item",
|
||||||
"fight_or_flight_option_2_label": "Steal the item",
|
"fight_or_flight_option_2_label": "Steal the item",
|
||||||
"fight_or_flight_option_2_tooltip": "@ecCol[SUMMARY_GREEN]{(35%) Steal Item}\n@ecCol[SUMMARY_BLUE]{(65%) Harder Battle}",
|
"fight_or_flight_option_2_tooltip": "@[SUMMARY_GREEN]{(35%) Steal Item}\n@[SUMMARY_BLUE]{(65%) Harder Battle}",
|
||||||
"fight_or_flight_option_2_steal_tooltip": "@ecCol[SUMMARY_GREEN]{(?) Use a Pokémon Move}",
|
"fight_or_flight_option_2_steal_tooltip": "@[SUMMARY_GREEN]{(?) Use a Pokémon Move}",
|
||||||
"fight_or_flight_option_3_label": "Leave",
|
"fight_or_flight_option_3_label": "Leave",
|
||||||
"fight_or_flight_option_3_tooltip": "(-) No Rewards",
|
"fight_or_flight_option_3_tooltip": "(-) No Rewards",
|
||||||
"fight_or_flight_option_1_selected_message": "You approach the\nPokémon without fear.",
|
"fight_or_flight_option_1_selected_message": "You approach the\nPokémon without fear.",
|
||||||
|
@ -167,7 +167,7 @@ export const mysteryEncounter: SimpleTranslationEntries = {
|
||||||
"sleeping_snorlax_option_1_label": "Fight it",
|
"sleeping_snorlax_option_1_label": "Fight it",
|
||||||
"sleeping_snorlax_option_1_tooltip": "(-) Fight Sleeping Snorlax",
|
"sleeping_snorlax_option_1_tooltip": "(-) Fight Sleeping Snorlax",
|
||||||
"sleeping_snorlax_option_2_label": "Wait for it to move",
|
"sleeping_snorlax_option_2_label": "Wait for it to move",
|
||||||
"sleeping_snorlax_option_2_tooltip": "@ecCol[SUMMARY_BLUE]{(75%) Wait a short time}\n@ecCol[SUMMARY_BLUE]{(25%) Wait a long time}",
|
"sleeping_snorlax_option_2_tooltip": "@[SUMMARY_BLUE]{(75%) Wait a short time}\n@[SUMMARY_BLUE]{(25%) Wait a long time}",
|
||||||
"sleeping_snorlax_option_3_label": "Steal",
|
"sleeping_snorlax_option_3_label": "Steal",
|
||||||
"sleeping_snorlax_option_3_tooltip": "(+) Leftovers",
|
"sleeping_snorlax_option_3_tooltip": "(+) Leftovers",
|
||||||
"sleeping_snorlax_option_3_disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
|
"sleeping_snorlax_option_3_disabled_tooltip": "Your Pokémon need to know certain moves to choose this",
|
||||||
|
|
|
@ -67,7 +67,7 @@ import { TrainerType } from "#enums/trainer-type";
|
||||||
import { BattlePhase } from "#app/phases/battle-phase";
|
import { BattlePhase } from "#app/phases/battle-phase";
|
||||||
import { MysteryEncounterVariant } from "#app/data/mystery-encounter";
|
import { MysteryEncounterVariant } from "#app/data/mystery-encounter";
|
||||||
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phase";
|
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phase";
|
||||||
import { getTextWithEncounterDialogueTokensAndColor, handleMysteryEncounterVictory } from "#app/data/mystery-encounters/mystery-encounter-utils";
|
import { getEncounterText, handleMysteryEncounterVictory } from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
|
||||||
|
|
||||||
const { t } = i18next;
|
const { t } = i18next;
|
||||||
|
@ -1081,8 +1081,8 @@ export class EncounterPhase extends BattlePhase {
|
||||||
const showNextDialogue = () => {
|
const showNextDialogue = () => {
|
||||||
const nextAction = i === introDialogue.length - 1 ? doShowEncounterOptions : showNextDialogue;
|
const nextAction = i === introDialogue.length - 1 ? doShowEncounterOptions : showNextDialogue;
|
||||||
const dialogue = introDialogue[i];
|
const dialogue = introDialogue[i];
|
||||||
const title = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.speaker);
|
const title = getEncounterText(this.scene, dialogue.speaker);
|
||||||
const text = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.text);
|
const text = getEncounterText(this.scene, dialogue.text);
|
||||||
if (title) {
|
if (title) {
|
||||||
this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 0 ? 750 : 0);
|
this.scene.ui.showDialogue(text, title, null, nextAction, 0, i === 0 ? 750 : 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import BattleScene from "../battle-scene";
|
||||||
import { Phase } from "../phase";
|
import { Phase } from "../phase";
|
||||||
import { Mode } from "../ui/ui";
|
import { Mode } from "../ui/ui";
|
||||||
import {
|
import {
|
||||||
getTextWithEncounterDialogueTokensAndColor
|
getEncounterText
|
||||||
} from "../data/mystery-encounters/mystery-encounter-utils";
|
} from "../data/mystery-encounters/mystery-encounter-utils";
|
||||||
import { CheckSwitchPhase, NewBattlePhase, PostSummonPhase, ReturnPhase, ScanIvsPhase, SummonPhase, ToggleDoublePositionPhase } from "../phases";
|
import { CheckSwitchPhase, NewBattlePhase, PostSummonPhase, ReturnPhase, ScanIvsPhase, SummonPhase, ToggleDoublePositionPhase } from "../phases";
|
||||||
import MysteryEncounterOption from "../data/mystery-encounter-option";
|
import MysteryEncounterOption from "../data/mystery-encounter-option";
|
||||||
|
@ -89,9 +89,9 @@ export class MysteryEncounterPhase extends Phase {
|
||||||
const nextAction = i === selectedDialogue.length - 1 ? endDialogueAndContinueEncounter : showNextDialogue;
|
const nextAction = i === selectedDialogue.length - 1 ? endDialogueAndContinueEncounter : showNextDialogue;
|
||||||
const dialogue = selectedDialogue[i];
|
const dialogue = selectedDialogue[i];
|
||||||
let title: string = null;
|
let title: string = null;
|
||||||
const text: string = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.text);
|
const text: string = getEncounterText(this.scene, dialogue.text);
|
||||||
if (dialogue.speaker) {
|
if (dialogue.speaker) {
|
||||||
title = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.speaker);
|
title = getEncounterText(this.scene, dialogue.speaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
|
@ -377,6 +377,7 @@ export class MysteryEncounterBattlePhase extends Phase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will handle (in order):
|
* Will handle (in order):
|
||||||
|
* - Any encounter reward logic that is set within MysteryEncounter doEncounterExp
|
||||||
* - Any encounter reward logic that is set within MysteryEncounter doEncounterRewards
|
* - Any encounter reward logic that is set within MysteryEncounter doEncounterRewards
|
||||||
* - Otherwise, can add a no-reward-item shop with only Potions, etc. if addHealPhase is true
|
* - Otherwise, can add a no-reward-item shop with only Potions, etc. if addHealPhase is true
|
||||||
* - Queuing of the PostMysteryEncounterPhase
|
* - Queuing of the PostMysteryEncounterPhase
|
||||||
|
@ -393,6 +394,10 @@ export class MysteryEncounterRewardsPhase extends Phase {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
this.scene.executeWithSeedOffset(() => {
|
this.scene.executeWithSeedOffset(() => {
|
||||||
|
if (this.scene.currentBattle.mysteryEncounter.doEncounterExp) {
|
||||||
|
this.scene.currentBattle.mysteryEncounter.doEncounterExp(this.scene);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
|
if (this.scene.currentBattle.mysteryEncounter.doEncounterRewards) {
|
||||||
this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
|
this.scene.currentBattle.mysteryEncounter.doEncounterRewards(this.scene);
|
||||||
} else if (this.addHealPhase) {
|
} else if (this.addHealPhase) {
|
||||||
|
@ -451,9 +456,9 @@ export class PostMysteryEncounterPhase extends Phase {
|
||||||
const nextAction = i === outroDialogue.length - 1 ? endPhase : showNextDialogue;
|
const nextAction = i === outroDialogue.length - 1 ? endPhase : showNextDialogue;
|
||||||
const dialogue = outroDialogue[i];
|
const dialogue = outroDialogue[i];
|
||||||
let title: string = null;
|
let title: string = null;
|
||||||
const text: string = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.text);
|
const text: string = getEncounterText(this.scene, dialogue.text);
|
||||||
if (dialogue.speaker) {
|
if (dialogue.speaker) {
|
||||||
title = getTextWithEncounterDialogueTokensAndColor(this.scene, dialogue.speaker);
|
title = getEncounterText(this.scene, dialogue.speaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import GameManager from "#app/test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import {
|
import {
|
||||||
getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon,
|
getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon,
|
||||||
getRandomPlayerPokemon, getRandomSpeciesByStarterTier, getTextWithEncounterDialogueTokensAndColor,
|
getRandomPlayerPokemon, getRandomSpeciesByStarterTier, getEncounterText,
|
||||||
koPlayerPokemon, queueEncounterMessage, showEncounterDialogue, showEncounterText,
|
koPlayerPokemon, queueEncounterMessage, showEncounterDialogue, showEncounterText,
|
||||||
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
import {initSceneWithoutEncounterPhase} from "#test/utils/gameManagerUtils";
|
import {initSceneWithoutEncounterPhase} from "#test/utils/gameManagerUtils";
|
||||||
|
@ -276,7 +276,7 @@ describe("Mystery Encounter Utils", () => {
|
||||||
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
scene.currentBattle.mysteryEncounter = new MysteryEncounter(null);
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||||
|
|
||||||
const result = getTextWithEncounterDialogueTokensAndColor(scene, "mysteryEncounter:unit_test_dialogue");
|
const result = getEncounterText(scene, "mysteryEncounter:unit_test_dialogue");
|
||||||
expect(result).toEqual("[color=#f8f8f8][shadow=#6b5a73]valuevalue @ec{testvalue} @ec{test1} value @ec{test\\} @ec{test\\} {test}[/color][/shadow]");
|
expect(result).toEqual("[color=#f8f8f8][shadow=#6b5a73]valuevalue @ec{testvalue} @ec{test1} value @ec{test\\} @ec{test\\} {test}[/color][/shadow]");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ describe("Mystery Encounter Utils", () => {
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
scene.currentBattle.mysteryEncounter.setDialogueToken("test", "value");
|
||||||
scene.currentBattle.mysteryEncounter.setDialogueToken("testvalue", "new");
|
scene.currentBattle.mysteryEncounter.setDialogueToken("testvalue", "new");
|
||||||
|
|
||||||
const result = getTextWithEncounterDialogueTokensAndColor(scene, "mysteryEncounter:unit_test_dialogue");
|
const result = getEncounterText(scene, "mysteryEncounter:unit_test_dialogue");
|
||||||
expect(result).toEqual("[color=#f8f8f8][shadow=#6b5a73]valuevalue new @ec{test1} value @ec{test\\} @ec{test\\} {test}[/color][/shadow]");
|
expect(result).toEqual("[color=#f8f8f8][shadow=#6b5a73]valuevalue new @ec{test1} value @ec{test\\} @ec{test\\} {test}[/color][/shadow]");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,7 +63,7 @@ describe("Mystery Encounter Phases", () => {
|
||||||
|
|
||||||
expect(game.scene.mysteryEncounterData.encounteredEvents.length).toBeGreaterThan(0);
|
expect(game.scene.mysteryEncounterData.encounteredEvents.length).toBeGreaterThan(0);
|
||||||
expect(game.scene.mysteryEncounterData.encounteredEvents[0][0]).toEqual(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
|
expect(game.scene.mysteryEncounterData.encounteredEvents[0][0]).toEqual(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
|
||||||
expect(game.scene.mysteryEncounterData.encounteredEvents[0][1]).toEqual(MysteryEncounterTier.UNCOMMON);
|
expect(game.scene.mysteryEncounterData.encounteredEvents[0][1]).toEqual(MysteryEncounterTier.GREAT);
|
||||||
expect(game.scene.ui.getMode()).toBe(Mode.MYSTERY_ENCOUNTER);
|
expect(game.scene.ui.getMode()).toBe(Mode.MYSTERY_ENCOUNTER);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import MysteryEncounterOption from "../data/mystery-encounter-option";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import {isNullOrUndefined} from "../utils";
|
import {isNullOrUndefined} from "../utils";
|
||||||
import {getPokeballAtlasKey} from "../data/pokeball";
|
import {getPokeballAtlasKey} from "../data/pokeball";
|
||||||
import {getTextWithEncounterDialogueTokensAndColor} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
import {getEncounterText} from "#app/data/mystery-encounters/mystery-encounter-utils";
|
||||||
|
|
||||||
export default class MysteryEncounterUiHandler extends UiHandler {
|
export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
private cursorContainer: Phaser.GameObjects.Container;
|
private cursorContainer: Phaser.GameObjects.Container;
|
||||||
|
@ -298,9 +298,9 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
this.filteredEncounterOptions = mysteryEncounter.options;
|
this.filteredEncounterOptions = mysteryEncounter.options;
|
||||||
this.optionsMeetsReqs = [];
|
this.optionsMeetsReqs = [];
|
||||||
|
|
||||||
const titleText: string = getTextWithEncounterDialogueTokensAndColor(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.title, TextStyle.TOOLTIP_TITLE);
|
const titleText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.title, TextStyle.TOOLTIP_TITLE);
|
||||||
const descriptionText: string = getTextWithEncounterDialogueTokensAndColor(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.description, TextStyle.TOOLTIP_CONTENT);
|
const descriptionText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.description, TextStyle.TOOLTIP_CONTENT);
|
||||||
const queryText: string = getTextWithEncounterDialogueTokensAndColor(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.query, TextStyle.TOOLTIP_CONTENT);
|
const queryText: string = getEncounterText(this.scene, mysteryEncounter.dialogue.encounterOptionsDialogue.query, TextStyle.TOOLTIP_CONTENT);
|
||||||
|
|
||||||
// Clear options container (except cursor)
|
// Clear options container (except cursor)
|
||||||
this.optionsContainer.removeAll();
|
this.optionsContainer.removeAll();
|
||||||
|
@ -320,7 +320,7 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[i];
|
const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[i];
|
||||||
const text = getTextWithEncounterDialogueTokensAndColor(this.scene, option.buttonLabel, option.style ? option.style : TextStyle.WINDOW);
|
const text = getEncounterText(this.scene, option.buttonLabel, option.style ? option.style : TextStyle.WINDOW);
|
||||||
if (text) {
|
if (text) {
|
||||||
optionText.setText(text);
|
optionText.setText(text);
|
||||||
}
|
}
|
||||||
|
@ -416,15 +416,15 @@ export default class MysteryEncounterUiHandler extends UiHandler {
|
||||||
let text;
|
let text;
|
||||||
const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor];
|
const option = mysteryEncounter.dialogue.encounterOptionsDialogue.options[cursor];
|
||||||
if (!this.optionsMeetsReqs[cursor] && option.disabledTooltip) {
|
if (!this.optionsMeetsReqs[cursor] && option.disabledTooltip) {
|
||||||
text = getTextWithEncounterDialogueTokensAndColor(this.scene, option.disabledTooltip, TextStyle.TOOLTIP_CONTENT);
|
text = getEncounterText(this.scene, option.disabledTooltip, TextStyle.TOOLTIP_CONTENT);
|
||||||
} else {
|
} else {
|
||||||
text = getTextWithEncounterDialogueTokensAndColor(this.scene, option.buttonTooltip, TextStyle.TOOLTIP_CONTENT);
|
text = getEncounterText(this.scene, option.buttonTooltip, TextStyle.TOOLTIP_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-color options green/blue for good/bad by looking for (+)/(-)
|
// Auto-color options green/blue for good/bad by looking for (+)/(-)
|
||||||
const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0];
|
const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0];
|
||||||
text = text.replace(/(\([^\(]*\+\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) + "[/color][/shadow]" + primaryStyleString);
|
text = text.replace(/(\(\+\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_GREEN) + "[/color][/shadow]" + primaryStyleString);
|
||||||
text = text.replace(/(\([^\(]*\-\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) + "[/color][/shadow]" + primaryStyleString);
|
text = text.replace(/(\(\-\)[^\(\[]*)/gi, substring => "[/color][/shadow]" + getBBCodeFrag(substring, TextStyle.SUMMARY_BLUE) + "[/color][/shadow]" + primaryStyleString);
|
||||||
|
|
||||||
if (text) {
|
if (text) {
|
||||||
const tooltipTextObject = addBBCodeTextObject(this.scene, 6, 7, text, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 600 }, fontSize: "72px" });
|
const tooltipTextObject = addBBCodeTextObject(this.scene, 6, 7, text, TextStyle.TOOLTIP_CONTENT, { wordWrap: { width: 600 }, fontSize: "72px" });
|
||||||
|
|
|
@ -171,6 +171,34 @@ export function getBBCodeFrag(content: string, textStyle: TextStyle, uiTheme: Ui
|
||||||
return `[color=${getTextColor(textStyle, false, uiTheme)}][shadow=${getTextColor(textStyle, true, uiTheme)}]${content}`;
|
return `[color=${getTextColor(textStyle, false, uiTheme)}][shadow=${getTextColor(textStyle, true, uiTheme)}]${content}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should only be used with BBCodeText (see addBBCodeTextObject())
|
||||||
|
* This does NOT work with UI showText() or showDialogue() methods.
|
||||||
|
* Method will do pattern match/replace and apply BBCode color/shadow styling to substrings within the content:
|
||||||
|
* @[<TextStyle>]{<text to color>}
|
||||||
|
*
|
||||||
|
* Example: passing a content string of "@[SUMMARY_BLUE]{blue text} primaryStyle text @[SUMMARY_RED]{red text}" will result in:
|
||||||
|
* - "blue text" with TextStyle.SUMMARY_BLUE applied
|
||||||
|
* - " primaryStyle text " with primaryStyle TextStyle applied
|
||||||
|
* - "red text" with TextStyle.SUMMARY_RED applied
|
||||||
|
* @param content - string with styling that need to be applied for BBCodeTextObject
|
||||||
|
* @param primaryStyle - primary style is required in order to escape BBCode styling properly.
|
||||||
|
* @param uiTheme
|
||||||
|
*/
|
||||||
|
export function getTextWithColors(content: string, primaryStyle: TextStyle, uiTheme: UiTheme = UiTheme.DEFAULT): string {
|
||||||
|
// Apply primary styling before anything else
|
||||||
|
let text = getBBCodeFrag(content, primaryStyle, uiTheme) + "[/color][/shadow]";
|
||||||
|
const primaryStyleString = [...text.match(new RegExp(/\[color=[^\[]*\]\[shadow=[^\[]*\]/i))][0];
|
||||||
|
|
||||||
|
// Set custom colors
|
||||||
|
text = text.replace(/@\[([^{]*)\]{([^}]*)}/gi, (substring, textStyle: string, textToColor: string) => {
|
||||||
|
return "[/color][/shadow]" + getBBCodeFrag(textToColor, TextStyle[textStyle], uiTheme) + "[/color][/shadow]" + primaryStyleString;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove extra style block at the end
|
||||||
|
return text.replace(/\[color=[^\[]*\]\[shadow=[^\[]*\]\[\/color\]\[\/shadow\]/gi, "");
|
||||||
|
}
|
||||||
|
|
||||||
export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: UiTheme = UiTheme.DEFAULT): string {
|
export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: UiTheme = UiTheme.DEFAULT): string {
|
||||||
switch (textStyle) {
|
switch (textStyle) {
|
||||||
case TextStyle.MESSAGE:
|
case TextStyle.MESSAGE:
|
||||||
|
|
Loading…
Reference in New Issue