Merge branch 'beta' into refactor-starter-handling

This commit is contained in:
Wlowscha 2025-09-04 18:03:01 +02:00 committed by GitHub
commit 9130709b6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 23 deletions

View File

@ -93,6 +93,7 @@ import { getEnumValues } from "#utils/enums";
import { toCamelCase, toTitleCase } from "#utils/strings"; import { toCamelCase, toTitleCase } from "#utils/strings";
import i18next from "i18next"; import i18next from "i18next";
import { applyChallenges } from "#utils/challenge-utils"; import { applyChallenges } from "#utils/challenge-utils";
import type { AbstractConstructor } from "#types/type-helpers";
/** /**
* A function used to conditionally determine execution of a given {@linkcode MoveAttr}. * A function used to conditionally determine execution of a given {@linkcode MoveAttr}.
@ -1055,16 +1056,11 @@ export class SelfStatusMove extends Move {
} }
} }
// TODO: Figure out how to improve the signature of this so that type SubMove = AbstractConstructor<Move>
// the `ChargeMove` function knows that the argument `Base` is a specific subclass of move that cannot
// be abstract.
// Right now, I only know how to do this by using the type conjunction (the & operators)
type SubMove = new (...args: any[]) => Move & {
is<K extends keyof MoveClassMap>(moveKind: K): this is MoveClassMap[K];
};
function ChargeMove<TBase extends SubMove>(Base: TBase, nameAppend: string) { function ChargeMove<TBase extends SubMove>(Base: TBase, nameAppend: string) {
return class extends Base { // NB: This cannot be made into a oneline return
abstract class Charging extends Base {
/** The animation to play during the move's charging phase */ /** The animation to play during the move's charging phase */
public readonly chargeAnim: ChargeAnim = ChargeAnim[`${MoveId[this.id]}_CHARGING`]; public readonly chargeAnim: ChargeAnim = ChargeAnim[`${MoveId[this.id]}_CHARGING`];
/** The message to show during the move's charging phase */ /** The message to show during the move's charging phase */
@ -1141,6 +1137,7 @@ function ChargeMove<TBase extends SubMove>(Base: TBase, nameAppend: string) {
return this; return this;
} }
}; };
return Charging;
} }
export class ChargingAttackMove extends ChargeMove(AttackMove, "ChargingAttackMove") {} export class ChargingAttackMove extends ChargeMove(AttackMove, "ChargingAttackMove") {}

View File

@ -562,6 +562,9 @@ export class PartyUiHandler extends MessageUiHandler {
private processModifierTransferModeInput(pokemon: PlayerPokemon) { private processModifierTransferModeInput(pokemon: PlayerPokemon) {
const ui = this.getUi(); const ui = this.getUi();
const option = this.options[this.optionsCursor]; const option = this.options[this.optionsCursor];
const allItems = this.getTransferrableItemsFromPokemon(pokemon);
// get the index of the "All" option.
const allCursorIndex = allItems.length;
if (this.transferMode && option === PartyOption.TRANSFER) { if (this.transferMode && option === PartyOption.TRANSFER) {
return this.processTransferOption(); return this.processTransferOption();
@ -573,31 +576,56 @@ export class PartyUiHandler extends MessageUiHandler {
let ableToTransferText: string; let ableToTransferText: string;
for (let p = 0; p < globalScene.getPlayerParty().length; p++) { for (let p = 0; p < globalScene.getPlayerParty().length; p++) {
// this for look goes through each of the party pokemon // this for loop goes through each of the party pokemon
const newPokemon = globalScene.getPlayerParty()[p]; const newPokemon = globalScene.getPlayerParty()[p];
// this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon `p` // this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon `p`
// this returns `undefined` if the new pokemon doesn't have the item at all, otherwise it returns the `pokemonHeldItemModifier` for that item // this returns `undefined` if the new pokemon doesn't have the item at all, otherwise it returns the `pokemonHeldItemModifier` for that item
const matchingModifier = globalScene.findModifier( const matchingModifiers: (PokemonHeldItemModifier | undefined)[] = [];
m => if (this.transferOptionCursor === allCursorIndex) {
m.is("PokemonHeldItemModifier") && // if "All" is selected, check all items
m.pokemonId === newPokemon.id && for (const item of allItems) {
m.matchType(this.getTransferrableItemsFromPokemon(pokemon)[this.transferOptionCursor]), matchingModifiers.push(
) as PokemonHeldItemModifier; globalScene.findModifier(
m => m.is("PokemonHeldItemModifier") && m.pokemonId === newPokemon.id && m.matchType(item),
) as PokemonHeldItemModifier | undefined,
);
}
} else {
// otherwise only check the selected item
matchingModifiers.push(
globalScene.findModifier(
m =>
m.is("PokemonHeldItemModifier") &&
m.pokemonId === newPokemon.id &&
m.matchType(allItems[this.transferOptionCursor]),
) as PokemonHeldItemModifier | undefined,
);
}
const hasMatchingModifier = matchingModifiers.some(m => m !== undefined); // checks if any items match
const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us
if (p !== this.transferCursor) { if (p !== this.transferCursor) {
// this skips adding the able/not able labels on the pokemon doing the transfer // this skips adding the able/not able labels on the pokemon doing the transfer
if (matchingModifier) { if (hasMatchingModifier) {
// if matchingModifier exists then the item exists on the new pokemon // if matchingModifier exists then the item exists on the new pokemon
if (matchingModifier.getMaxStackCount() === matchingModifier.stackCount) { ableToTransferText = i18next.t("partyUiHandler:notAble"); // start with not able
// checks to see if the stack of items is at max stack; if so, set the description label to "Not able" /**
ableToTransferText = i18next.t("partyUiHandler:notAble"); * The amount of items that can be transferred in the `All` option
} else { */
// if the pokemon isn't at max stack, make the label "Able" let ableAmount = 0;
ableToTransferText = i18next.t("partyUiHandler:able"); for (const modifier of matchingModifiers) {
if (!modifier || modifier.getCountUnderMax() > 0) {
// if the modifier doesn't exist, or the stack count isn't at max, then we can transfer at least 1 stack
ableToTransferText = i18next.t("partyUiHandler:able");
ableAmount++;
}
} }
// only show the amount if an item can be transferred and there are multiple items
ableToTransferText += ableAmount && matchingModifiers.length > 1 ? ` (${ableAmount})` : "";
} else { } else {
// if matchingModifier doesn't exist, that means the pokemon doesn't have any of the item, and we need to show "Able" // if no item matches, that means the pokemon doesn't have any of the item, and we need to show "Able"
ableToTransferText = i18next.t("partyUiHandler:able"); ableToTransferText = i18next.t("partyUiHandler:able");
// only show the amount if there are multiple items
ableToTransferText += matchingModifiers.length > 1 ? ` (${matchingModifiers.length})` : "";
} }
} else { } else {
// this else relates to the transfer pokemon. We set the text to be blank so there's no "Able"/"Not able" text // this else relates to the transfer pokemon. We set the text to be blank so there's no "Able"/"Not able" text
@ -1645,6 +1673,8 @@ export class PartyUiHandler extends MessageUiHandler {
.find(plm => plm[1] === move); .find(plm => plm[1] === move);
} else if (option === PartyOption.ALL) { } else if (option === PartyOption.ALL) {
optionName = i18next.t("partyUiHandler:all"); optionName = i18next.t("partyUiHandler:all");
// add the number of items to the `all` option
optionName += ` (${this.getTransferrableItemsFromPokemon(pokemon).length})`;
} else { } else {
const itemModifiers = this.getItemModifiers(pokemon); const itemModifiers = this.getItemModifiers(pokemon);
const itemModifier = itemModifiers[option]; const itemModifier = itemModifiers[option];