Working leftovers in new style

This commit is contained in:
Wlowscha 2025-05-30 01:50:15 +02:00
parent 77f8cd9643
commit 3f045ec7a6
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
8 changed files with 109 additions and 47 deletions

View File

@ -122,7 +122,7 @@ import { MoveFlags } from "#enums/MoveFlags";
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger"; import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
import { MultiHitType } from "#enums/MultiHitType"; import { MultiHitType } from "#enums/MultiHitType";
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves"; import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
import { applyAttackTypeBoosterHeldItem } from "#app/modifier/held-items"; import { applyAttackTypeBoosterHeldItem } from "#app/modifier/all-held-items";
import { TrainerVariant } from "#app/field/trainer"; import { TrainerVariant } from "#app/field/trainer";
import { SelectBiomePhase } from "#app/phases/select-biome-phase"; import { SelectBiomePhase } from "#app/phases/select-biome-phase";

View File

@ -74,3 +74,15 @@ export const HeldItems = {
}; };
export type HeldItems = (typeof HeldItems)[keyof typeof HeldItems]; export type HeldItems = (typeof HeldItems)[keyof typeof HeldItems];
type HeldItemName = keyof typeof HeldItems;
type HeldItemValue = typeof HeldItems[HeldItemName];
// Use a type-safe reducer to force number keys and values
export const HeldItemNames: Record<HeldItemValue, HeldItemName> = Object.entries(HeldItems).reduce(
(acc, [key, value]) => {
acc[value as HeldItemValue] = key as HeldItemName;
return acc;
},
{} as Record<HeldItemValue, HeldItemName>
);

View File

@ -1,8 +1,10 @@
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/interfaces/locales";
import type { NumberHolder } from "#app/utils/common"; import { getPokemonNameWithAffix } from "#app/messages";
import { HeldItems } from "#enums/held-items"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { toDmgValue, type NumberHolder } from "#app/utils/common";
import { HeldItemNames, HeldItems } from "#enums/held-items";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import i18next from "i18next"; import i18next from "i18next";
@ -137,7 +139,7 @@ export class AttackTypeBoosterHeldItem extends HeldItem {
} }
getName(): string { getName(): string {
return i18next.t(`modifierType:AttackTypeBoosterItem.${HeldItems[this.type]?.toLowerCase()}`); return i18next.t(`modifierType:AttackTypeBoosterItem.${HeldItemNames[this.type]?.toLowerCase()}`);
} }
getDescription(): string { getDescription(): string {
@ -147,7 +149,7 @@ export class AttackTypeBoosterHeldItem extends HeldItem {
} }
getIcon(): string { getIcon(): string {
return `${HeldItems[this.type]?.toLowerCase()}`; return `${HeldItemNames[this.type]?.toLowerCase()}`;
} }
apply(stackCount: number, moveType: PokemonType, movePower: NumberHolder): void { apply(stackCount: number, moveType: PokemonType, movePower: NumberHolder): void {
@ -167,6 +169,48 @@ export function applyAttackTypeBoosterHeldItem(pokemon: Pokemon, moveType: Pokem
} }
} }
export class TurnHealHeldItem extends HeldItem {
getName(): string {
return i18next.t("modifierType:ModifierType.LEFTOVERS.name") + " (new)";
}
getDescription(): string {
return i18next.t("modifierType:ModifierType.LEFTOVERS.description");
}
getIcon(): string {
return "leftovers";
}
apply(stackCount: number, pokemon: Pokemon): boolean {
if (!pokemon.isFullHp()) {
globalScene.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16) * stackCount,
i18next.t("modifier:turnHealApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
typeName: this.name,
}),
true,
),
);
return true;
}
return false;
}
}
export function applyTurnHealHeldItem(pokemon: Pokemon) {
if (pokemon) {
for (const [item, props] of Object.entries(pokemon.heldItemManager.getHeldItems())) {
if (allHeldItems[item] instanceof TurnHealHeldItem) {
allHeldItems[item].apply(props.stack, pokemon);
}
}
}
}
export const allHeldItems = {}; export const allHeldItems = {};
export function initHeldItems() { export function initHeldItems() {
@ -175,4 +219,6 @@ export function initHeldItems() {
const pokemonType = Number(typeKey) as PokemonType; const pokemonType = Number(typeKey) as PokemonType;
allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2); allHeldItems[heldItemType] = new AttackTypeBoosterHeldItem(heldItemType, 99, pokemonType, 0.2);
} }
allHeldItems[HeldItems.LEFTOVERS] = new TurnHealHeldItem(HeldItems.LEFTOVERS, 4);
console.log(allHeldItems);
} }

View File

@ -129,7 +129,7 @@ import { getStatKey, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import i18next from "i18next"; import i18next from "i18next";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import type { HeldItems } from "#enums/held-items"; import { HeldItems } from "#enums/held-items";
import { allHeldItems, attackTypeToHeldItem } from "./all-held-items"; import { allHeldItems, attackTypeToHeldItem } from "./all-held-items";
import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants"; import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants";
@ -177,6 +177,10 @@ export class ModifierType {
return i18next.t(`${this.localeKey}.description` as any); return i18next.t(`${this.localeKey}.description` as any);
} }
getIcon(): string {
return this.iconImage;
}
setTier(tier: ModifierTier): void { setTier(tier: ModifierTier): void {
this.tier = tier; this.tier = tier;
} }
@ -423,17 +427,10 @@ export class PokemonHeldItemModifierType extends PokemonModifierType {
export class PokemonHeldItemReward extends PokemonModifierType { export class PokemonHeldItemReward extends PokemonModifierType {
public itemId: HeldItems; public itemId: HeldItems;
constructor( constructor(itemId: HeldItems, newModifierFunc: NewModifierFunc, group?: string, soundName?: string) {
itemId: HeldItems,
localeKey: string,
iconImage: string,
newModifierFunc: NewModifierFunc,
group?: string,
soundName?: string,
) {
super( super(
localeKey, "",
iconImage, "",
newModifierFunc, newModifierFunc,
(pokemon: PlayerPokemon) => { (pokemon: PlayerPokemon) => {
const hasItem = pokemon.heldItemManager.hasItem(this.itemId); const hasItem = pokemon.heldItemManager.hasItem(this.itemId);
@ -465,9 +462,12 @@ export class PokemonHeldItemReward extends PokemonModifierType {
} }
getDescription(): string { getDescription(): string {
// TODO: Need getTypeName?
return allHeldItems[this.itemId].getDescription(); return allHeldItems[this.itemId].getDescription();
} }
getIcon(): string {
return allHeldItems[this.itemId].getIcon();
}
} }
export class TerastallizeModifierType extends PokemonModifierType { export class TerastallizeModifierType extends PokemonModifierType {
@ -866,8 +866,7 @@ export class AttackTypeBoosterReward extends PokemonHeldItemReward implements Ge
const itemId = attackTypeToHeldItem[moveType]; const itemId = attackTypeToHeldItem[moveType];
super( super(
itemId, itemId,
"", // Next argument is useless
allHeldItems[itemId].getIcon(),
(_type, args) => new AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent), (_type, args) => new AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent),
); );
this.moveType = moveType; this.moveType = moveType;
@ -2016,7 +2015,7 @@ export type GeneratorModifierOverride = {
type?: Nature; type?: Nature;
} }
| { | {
name: keyof Pick<typeof modifierTypes, "ATTACK_TYPE_BOOSTER" | "TERA_SHARD">; name: keyof Pick<typeof modifierTypes, "ATTACK_TYPE_BOOSTER_REWARD" | "ATTACK_TYPE_BOOSTER" | "TERA_SHARD">;
type?: PokemonType; type?: PokemonType;
} }
| { | {
@ -2371,6 +2370,9 @@ export const modifierTypes = {
(type, args) => new FlinchChanceModifier(type, (args[0] as Pokemon).id), (type, args) => new FlinchChanceModifier(type, (args[0] as Pokemon).id),
), ),
LEFTOVERS_REWARD: () =>
new PokemonHeldItemReward(HeldItems.LEFTOVERS, (type, args) => new TurnHealModifier(type, (args[0] as Pokemon).id)),
LEFTOVERS: () => LEFTOVERS: () =>
new PokemonHeldItemModifierType( new PokemonHeldItemModifierType(
"modifierType:ModifierType.LEFTOVERS", "modifierType:ModifierType.LEFTOVERS",
@ -3058,7 +3060,7 @@ const modifierPool: ModifierPool = {
[ModifierTier.ROGUE]: [ [ModifierTier.ROGUE]: [
new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16), new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16),
new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)), new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)),
new WeightedModifierType(modifierTypes.LEFTOVERS, 3), new WeightedModifierType(modifierTypes.LEFTOVERS_REWARD, 3),
new WeightedModifierType(modifierTypes.SHELL_BELL, 3), new WeightedModifierType(modifierTypes.SHELL_BELL, 3),
new WeightedModifierType(modifierTypes.BERRY_POUCH, 4), new WeightedModifierType(modifierTypes.BERRY_POUCH, 4),
new WeightedModifierType(modifierTypes.GRIP_CLAW, 5), new WeightedModifierType(modifierTypes.GRIP_CLAW, 5),

View File

@ -718,7 +718,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier {
const item = globalScene.add.sprite(16, this.virtualStackCount ? 8 : 16, "items"); const item = globalScene.add.sprite(16, this.virtualStackCount ? 8 : 16, "items");
item.setScale(0.5); item.setScale(0.5);
item.setOrigin(0, 0.5); item.setOrigin(0, 0.5);
item.setTexture("items", this.type.iconImage); item.setTexture("items", this.type.getIcon());
container.add(item); container.add(item);
const stackText = this.getIconStackText(); const stackText = this.getIconStackText();

View File

@ -161,8 +161,7 @@ export class SelectModifierPhase extends BattlePhase {
//TODO: is the bang correct? //TODO: is the bang correct?
if (modifierType instanceof PokemonHeldItemReward) { if (modifierType instanceof PokemonHeldItemReward) {
this.openGiveHeldItemMenu(modifierType, modifierSelectCallback); this.openGiveHeldItemMenu(modifierType, modifierSelectCallback);
} } else if (modifierType instanceof FusePokemonModifierType) {
if (modifierType instanceof FusePokemonModifierType) {
this.openFusionMenu(modifierType, cost, modifierSelectCallback); this.openFusionMenu(modifierType, cost, modifierSelectCallback);
} else { } else {
this.openModifierMenu(modifierType, cost, modifierSelectCallback); this.openModifierMenu(modifierType, cost, modifierSelectCallback);
@ -235,26 +234,6 @@ export class SelectModifierPhase extends BattlePhase {
return true; return true;
} }
private openGiveHeldItemMenu(reward, modifierSelectCallback) {
const party = globalScene.getPlayerParty();
const partyUiMode = PartyUiMode.MODIFIER;
globalScene.ui.setModeWithoutClear(
UiMode.PARTY,
partyUiMode,
-1,
(slotIndex: number, _option: PartyOption) => {
if (slotIndex < 6) {
globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => {
party[slotIndex].heldItemManager.addHeldItem(reward.itemId);
});
} else {
this.resetModifierSelect(modifierSelectCallback);
}
},
reward.selectFilter,
);
}
// Toggle reroll lock // Toggle reroll lock
private toggleRerollLock() { private toggleRerollLock() {
const rerollCost = this.getRerollCost(globalScene.lockModifierTiers); const rerollCost = this.getRerollCost(globalScene.lockModifierTiers);
@ -370,6 +349,29 @@ export class SelectModifierPhase extends BattlePhase {
); );
} }
private openGiveHeldItemMenu(reward, modifierSelectCallback) {
const party = globalScene.getPlayerParty();
const partyUiMode = PartyUiMode.MODIFIER;
globalScene.ui.setModeWithoutClear(
UiMode.PARTY,
partyUiMode,
-1,
(slotIndex: number, _option: PartyOption) => {
if (slotIndex < 6) {
globalScene.ui.setMode(UiMode.MODIFIER_SELECT, this.isPlayer()).then(() => {
party[slotIndex].heldItemManager.addHeldItem(reward.itemId);
globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.MESSAGE);
super.end();
});
} else {
this.resetModifierSelect(modifierSelectCallback);
}
},
reward.selectFilter,
);
}
// Function that determines how many reward slots are available // Function that determines how many reward slots are available
private getModifierCount(): number { private getModifierCount(): number {
const modifierCountHolder = new NumberHolder(3); const modifierCountHolder = new NumberHolder(3);

View File

@ -6,7 +6,6 @@ import { TurnEndEvent } from "#app/events/battle-scene";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { import {
TurnHealModifier,
EnemyTurnHealModifier, EnemyTurnHealModifier,
EnemyStatusEffectHealChanceModifier, EnemyStatusEffectHealChanceModifier,
TurnStatusEffectModifier, TurnStatusEffectModifier,
@ -16,6 +15,7 @@ import i18next from "i18next";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { PokemonHealPhase } from "./pokemon-heal-phase"; import { PokemonHealPhase } from "./pokemon-heal-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { applyTurnHealHeldItem } from "#app/modifier/all-held-items";
export class TurnEndPhase extends FieldPhase { export class TurnEndPhase extends FieldPhase {
start() { start() {
@ -30,7 +30,7 @@ export class TurnEndPhase extends FieldPhase {
if (!pokemon.switchOutStatus) { if (!pokemon.switchOutStatus) {
pokemon.lapseTags(BattlerTagLapseType.TURN_END); pokemon.lapseTags(BattlerTagLapseType.TURN_END);
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon); applyTurnHealHeldItem(pokemon);
if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) { if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) {
globalScene.unshiftPhase( globalScene.unshiftPhase(

View File

@ -763,7 +763,7 @@ class ModifierOption extends Phaser.GameObjects.Container {
this.add(this.itemContainer); this.add(this.itemContainer);
const getItem = () => { const getItem = () => {
const item = globalScene.add.sprite(0, 0, "items", this.modifierTypeOption.type?.iconImage); const item = globalScene.add.sprite(0, 0, "items", this.modifierTypeOption.type?.getIcon());
return item; return item;
}; };