Add Memory Mushroom to Shop + escape TM selection

This commit is contained in:
innerthunder 2024-10-02 22:37:42 -07:00
parent f634b7c044
commit b7516349a0
6 changed files with 61 additions and 28 deletions

View File

@ -4,7 +4,7 @@ import Pokemon, { EnemyPokemon, PlayerPokemon } from "./field/pokemon";
import PokemonSpecies, { allSpecies, getPokemonSpecies, PokemonSpeciesFilter } from "./data/pokemon-species";
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
import * as Utils from "./utils";
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { ConsumableModifier, ConsumablePokemonModifier, DoubleBattleChanceBoosterModifier, ExpBalanceModifier, ExpShareModifier, FusePokemonModifier, HealingBoosterModifier, Modifier, ModifierBar, ModifierPredicate, MultipleParticipantExpBonusModifier, overrideHeldItems, overrideModifiers, PersistentModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, RememberMoveModifier, TerastallizeModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball";
import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from "./data/battle-anims";
import { Phase } from "./phase";
@ -2429,7 +2429,7 @@ export default class BattleScene extends SceneBase {
return Math.floor(moneyValue / 10) * 10;
}
addModifier(modifier: Modifier | null, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<boolean> {
addModifier(modifier: Modifier | null, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean, cost?: number): Promise<boolean> {
if (!modifier) {
return Promise.resolve(false);
}
@ -2483,6 +2483,8 @@ export default class BattleScene extends SceneBase {
}
} else if (modifier instanceof FusePokemonModifier) {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} else if (modifier instanceof RememberMoveModifier) {
args.push(cost);
}
if (modifier.shouldApply(args)) {

View File

@ -2226,7 +2226,8 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, base
],
[
new ModifierTypeOption(modifierTypes.ELIXIR(), 0, baseCost),
new ModifierTypeOption(modifierTypes.MAX_ETHER(), 0, baseCost)
new ModifierTypeOption(modifierTypes.MAX_ETHER(), 0, baseCost),
new ModifierTypeOption(modifierTypes.MEMORY_MUSHROOM(), 0, baseCost * 2)
],
[
new ModifierTypeOption(modifierTypes.HYPER_POTION(), 0, baseCost * 0.8),

View File

@ -2005,8 +2005,9 @@ export class RememberMoveModifier extends ConsumablePokemonModifier {
apply(args: any[]): boolean {
const pokemon = args[0] as PlayerPokemon;
const cost = args[1] as number;
pokemon.scene.unshiftPhase(new LearnMovePhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.getLearnableLevelMoves()[this.levelMoveIndex]));
pokemon.scene.unshiftPhase(new LearnMovePhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.getLearnableLevelMoves()[this.levelMoveIndex], false, cost));
return true;
}

View File

@ -2,24 +2,28 @@ import BattleScene from "#app/battle-scene";
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
import Move, { allMoves } from "#app/data/move";
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms";
import { Moves } from "#app/enums/moves";
import { Moves } from "#enums/moves";
import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides";
import EvolutionSceneHandler from "#app/ui/evolution-scene-handler";
import { SummaryUiMode } from "#app/ui/summary-ui-handler";
import { Mode } from "#app/ui/ui";
import i18next from "i18next";
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase";
import Pokemon from "#app/field/pokemon";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
private moveId: Moves;
private messageMode: Mode;
private fromTM: boolean;
private cost: number;
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves, fromTM?: boolean) {
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves, fromTM?: boolean, cost: number = -1) {
super(scene, partyMemberIndex);
this.moveId = moveId;
this.fromTM = fromTM ?? false;
this.cost = cost;
}
start() {
@ -143,6 +147,17 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
pokemon.usedTMs.push(this.moveId);
}
pokemon.setMove(index, this.moveId);
if (this.cost !== -1) {
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
this.scene.money -= this.cost;
this.scene.updateMoneyText();
this.scene.animateMoneyChanged(false);
}
this.scene.playSound("se/buy");
} else if (this.fromTM) {
// NOTE: this assumes
this.scene.tryRemovePhase((phase) => phase instanceof SelectModifierPhase);
}
initMoveAnim(this.scene, this.moveId).then(() => {
loadMoveAnimAssets(this.scene, [this.moveId], true);
this.scene.playSound("level_up_fanfare"); // Sound loaded into game as is

View File

@ -17,6 +17,8 @@ export class SelectModifierPhase extends BattlePhase {
private modifierTiers?: ModifierTier[];
private customModifierSettings?: CustomModifierSettings;
private typeOptions: ModifierTypeOption[];
constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[], customModifierSettings?: CustomModifierSettings) {
super(scene);
@ -54,7 +56,7 @@ export class SelectModifierPhase extends BattlePhase {
}
}
const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value);
this.typeOptions = this.getModifierTypeOptions(modifierCount.value);
const modifierSelectCallback = (rowCursor: integer, cursor: integer) => {
if (rowCursor < 0 || cursor < 0) {
@ -63,13 +65,13 @@ export class SelectModifierPhase extends BattlePhase {
this.scene.ui.revertMode();
this.scene.ui.setMode(Mode.MESSAGE);
super.end();
}, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)));
}, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers)));
});
return false;
}
let modifierType: ModifierType;
let cost: integer;
const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers);
const rerollCost = this.getRerollCost(this.scene.lockModifierTiers);
switch (rowCursor) {
case 0:
switch (cursor) {
@ -79,7 +81,7 @@ export class SelectModifierPhase extends BattlePhase {
return false;
} else {
this.scene.reroll = true;
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[]));
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, this.typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[]));
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
@ -98,13 +100,13 @@ export class SelectModifierPhase extends BattlePhase {
const itemModifier = itemModifiers[itemIndex];
this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity);
} else {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers));
}
}, PartyUiHandler.FilterItemMaxStacks);
break;
case 2:
this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.CHECK, -1, () => {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers));
});
break;
case 3:
@ -115,21 +117,21 @@ export class SelectModifierPhase extends BattlePhase {
}
this.scene.lockModifierTiers = !this.scene.lockModifierTiers;
const uiHandler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
uiHandler.setRerollCost(this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
uiHandler.setRerollCost(this.getRerollCost(this.scene.lockModifierTiers));
uiHandler.updateLockRaritiesText();
uiHandler.updateRerollCostText();
return false;
}
return true;
case 1:
if (typeOptions.length === 0) {
if (this.typeOptions.length === 0) {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE);
super.end();
return true;
}
if (typeOptions[cursor].type) {
modifierType = typeOptions[cursor].type;
if (this.typeOptions[cursor].type) {
modifierType = this.typeOptions[cursor].type;
}
break;
default:
@ -151,8 +153,16 @@ export class SelectModifierPhase extends BattlePhase {
}
const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
const result = this.scene.addModifier(modifier, false, playSound);
if (cost) {
const result = this.scene.addModifier(modifier, false, playSound, undefined, undefined, cost);
// Queue a copy of this phase when applying a TM or Memory Mushroom.
// If the player selects either of these, then escapes out of consuming them,
// they are returned to a shop in the same state.
if (modifier.type instanceof RememberMoveModifierType ||
modifier.type instanceof TmModifierType) {
this.scene.unshiftPhase(this.copy());
}
if (cost && !(modifier.type instanceof RememberMoveModifierType)) {
result.then(success => {
if (success) {
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
@ -189,7 +199,7 @@ export class SelectModifierPhase extends BattlePhase {
applyModifier(modifier, true);
});
} else {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers));
}
}, modifierType.selectFilter);
} else {
@ -216,7 +226,7 @@ export class SelectModifierPhase extends BattlePhase {
applyModifier(modifier!, true); // TODO: is the bang correct?
});
} else {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers));
}
}, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier);
}
@ -226,7 +236,7 @@ export class SelectModifierPhase extends BattlePhase {
return !cost!;// TODO: is the bang correct?
};
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), this.typeOptions, modifierSelectCallback, this.getRerollCost(this.scene.lockModifierTiers));
}
updateSeed(): void {
@ -237,13 +247,13 @@ export class SelectModifierPhase extends BattlePhase {
return true;
}
getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): number {
getRerollCost(lockRarities: boolean): number {
let baseValue = 0;
if (Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
return baseValue;
} else if (lockRarities) {
const tierValues = [50, 125, 300, 750, 2000];
for (const opt of typeOptions) {
for (const opt of this.typeOptions) {
baseValue += tierValues[opt.type.tier ?? 0];
}
} else {
@ -271,6 +281,10 @@ export class SelectModifierPhase extends BattlePhase {
return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined, this.customModifierSettings);
}
copy(): SelectModifierPhase {
return new SelectModifierPhase(this.scene, this.rerollCount, this.modifierTiers, {guaranteedModifierTypeOptions: this.typeOptions});
}
addModifier(modifier: Modifier): Promise<boolean> {
return this.scene.addModifier(modifier, false, true);
}

View File

@ -63,11 +63,11 @@ describe("SelectModifierPhase", () => {
new ModifierTypeOption(modifierTypes.REVIVE(), 0, 1000)
];
const selectModifierPhase1 = new SelectModifierPhase(scene);
const selectModifierPhase2 = new SelectModifierPhase(scene, 0, undefined, { rerollMultiplier: 2 });
const selectModifierPhase1 = new SelectModifierPhase(scene, 0, undefined, { guaranteedModifierTypeOptions: options });
const selectModifierPhase2 = new SelectModifierPhase(scene, 0, undefined, { guaranteedModifierTypeOptions: options, rerollMultiplier: 2 });
const cost1 = selectModifierPhase1.getRerollCost(options, false);
const cost2 = selectModifierPhase2.getRerollCost(options, false);
const cost1 = selectModifierPhase1.getRerollCost(false);
const cost2 = selectModifierPhase2.getRerollCost(false);
expect(cost2).toEqual(cost1 * 2);
});