diff --git a/public/images/items.json b/public/images/items.json index 40c14389ab2..d199f4c3d35 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -8618,6 +8618,132 @@ "w": 16, "h": 16 } + }, + { + "filename": "repb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 204, + "y": 423, + "w": 20, + "h": 20 + } + }, + { + "filename": "tb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 224, + "y": 423, + "w": 20, + "h": 20 + } + }, + { + "filename": "sb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 244, + "y": 423, + "w": 20, + "h": 20 + } + }, + { + "filename": "qb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 264, + "y": 423, + "w": 20, + "h": 20 + } + }, + { + "filename": "preb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, + "frame": { + "x": 284, + "y": 425, + "w": 20, + "h": 18 + } + }, + { + "filename": "lb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 20, + "h": 20 + }, + "frame": { + "x": 304, + "y": 425, + "w": 20, + "h": 18 + } } ] } diff --git a/public/images/items.png b/public/images/items.png index ecc8d42daea..11a89e61a4e 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/public/images/items/lb.png b/public/images/items/lb.png new file mode 100644 index 00000000000..124b0aedf81 Binary files /dev/null and b/public/images/items/lb.png differ diff --git a/public/images/items/preb.png b/public/images/items/preb.png new file mode 100644 index 00000000000..0f04811e258 Binary files /dev/null and b/public/images/items/preb.png differ diff --git a/public/images/items/qb.png b/public/images/items/qb.png new file mode 100644 index 00000000000..554cea483cd Binary files /dev/null and b/public/images/items/qb.png differ diff --git a/public/images/items/repb.png b/public/images/items/repb.png new file mode 100644 index 00000000000..34ced039e6d Binary files /dev/null and b/public/images/items/repb.png differ diff --git a/public/images/items/sb.png b/public/images/items/sb.png new file mode 100644 index 00000000000..2f79f832082 Binary files /dev/null and b/public/images/items/sb.png differ diff --git a/public/images/items/tb.png b/public/images/items/tb.png new file mode 100644 index 00000000000..1d899d8cda5 Binary files /dev/null and b/public/images/items/tb.png differ diff --git a/public/images/pb.json b/public/images/pb.json index fe11336cf82..a533880e68c 100644 --- a/public/images/pb.json +++ b/public/images/pb.json @@ -386,6 +386,321 @@ "w": 12, "h": 12 } + }, + { + "filename": "repb_open", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 12, + "h": 16 + }, + "frame": { + "x": 0, + "y": 246, + "w": 12, + "h": 16 + } + }, + { + "filename": "repb_opening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 12, + "h": 13 + }, + "frame": { + "x": 0, + "y": 262, + "w": 12, + "h": 13 + } + }, + { + "filename": "repb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 4, + "w": 12, + "h": 12 + }, + "frame": { + "x": 0, + "y": 276, + "w": 12, + "h": 12 + } + }, + { + "filename": "tb_open", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 12, + "h": 16 + }, + "frame": { + "x": 0, + "y": 288, + "w": 12, + "h": 16 + } + }, + { + "filename": "tb_opening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 12, + "h": 13 + }, + "frame": { + "x": 0, + "y": 304, + "w": 12, + "h": 13 + } + }, + { + "filename": "tb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 4, + "w": 12, + "h": 12 + }, + "frame": { + "x": 0, + "y": 318, + "w": 12, + "h": 12 + } + }, + { + "filename": "sb_open", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 12, + "h": 16 + }, + "frame": { + "x": 0, + "y": 330, + "w": 12, + "h": 16 + } + }, + { + "filename": "sb_opening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 12, + "h": 13 + }, + "frame": { + "x": 0, + "y": 346, + "w": 12, + "h": 13 + } + }, + { + "filename": "sb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 4, + "w": 12, + "h": 12 + }, + "frame": { + "x": 0, + "y": 360, + "w": 12, + "h": 12 + } + }, + { + "filename": "qb_open", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 12, + "h": 16 + }, + "frame": { + "x": 0, + "y": 372, + "w": 12, + "h": 16 + } + }, + { + "filename": "qb_opening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 12, + "h": 13 + }, + "frame": { + "x": 0, + "y": 388, + "w": 12, + "h": 13 + } + }, + { + "filename": "qb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 4, + "w": 12, + "h": 12 + }, + "frame": { + "x": 0, + "y": 402, + "w": 12, + "h": 12 + } + }, + { + "filename": "preb_open", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 12, + "h": 16 + }, + "frame": { + "x": 0, + "y": 414, + "w": 12, + "h": 16 + } + }, + { + "filename": "preb_opening", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 3, + "w": 12, + "h": 13 + }, + "frame": { + "x": 0, + "y": 430, + "w": 12, + "h": 13 + } + }, + { + "filename": "preb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 12, + "h": 16 + }, + "spriteSourceSize": { + "x": 0, + "y": 4, + "w": 12, + "h": 12 + }, + "frame": { + "x": 0, + "y": 444, + "w": 12, + "h": 12 + } } ] } diff --git a/public/images/pb.png b/public/images/pb.png index 364d864f7fe..84edbac3fc9 100644 Binary files a/public/images/pb.png and b/public/images/pb.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 9bb76b6fd23..621c4df6bcd 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -271,6 +271,8 @@ export class BattleScene extends SceneBase { public lastEnemyTrainer: Trainer | null; public currentBattle: Battle; public pokeballCounts: PokeballCounts; + public lastPokeballType: PokeballType = PokeballType.POKEBALL; + public premierPokeballMultiplier: number = 1; public money: number; public pokemonInfoContainer: PokemonInfoContainer; private party: PlayerPokemon[]; @@ -1148,12 +1150,14 @@ export class BattleScene extends SceneBase { this.score = 0; this.money = 0; + this.lastPokeballType = PokeballType.POKEBALL; + this.premierPokeballMultiplier = 1; this.lockModifierTiers = false; this.pokeballCounts = Object.fromEntries( getEnumValues(PokeballType) - .filter(p => p <= PokeballType.MASTER_BALL) + .filter(p => p <= PokeballType.REPEAT_BALL) .map(t => [t, 0]), ); this.pokeballCounts[PokeballType.POKEBALL] += 5; diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index 764951877f0..d940987ca68 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -22,7 +22,7 @@ import { doPlayerFlee, doPokemonFlee, getRandomSpeciesByStarterCost, - trainerThrowPokeball, + trainerThrowSafariball, } from "#mystery-encounters/encounter-pokemon-utils"; import type { MysteryEncounter } from "#mystery-encounters/mystery-encounter"; import { MysteryEncounterBuilder } from "#mystery-encounters/mystery-encounter"; @@ -349,7 +349,7 @@ function throwPokeball(pokemon: EnemyPokemon): Promise { const pokeballMultiplier = 1.5; const catchRate = Math.round(baseCatchRate * pokeballMultiplier * safariModifier); const ballTwitchRate = Math.round(1048560 / Math.sqrt(Math.sqrt(16711680 / catchRate))); - return trainerThrowPokeball(pokemon, PokeballType.POKEBALL, ballTwitchRate); + return trainerThrowSafariball(pokemon, PokeballType.SAFARI_BALL, ballTwitchRate); } async function throwBait(pokemon: EnemyPokemon): Promise { diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index 93ef59d6ee7..4caaabbc697 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -439,7 +439,7 @@ export async function applyModifierTypeToPlayerPokemon( * @param pokeballType * @param ballTwitchRate - can pass custom ball catch rates (for special events, like safari) */ -export function trainerThrowPokeball( +export function trainerThrowSafariball( pokemon: EnemyPokemon, pokeballType: PokeballType, ballTwitchRate?: number, diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index 50ea5076aee..0cbdc5e053e 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -19,6 +19,19 @@ export function getPokeballAtlasKey(type: PokeballType): string { return "mb"; case PokeballType.LUXURY_BALL: return "lb"; + case PokeballType.QUICK_BALL: + return "qb"; + case PokeballType.TIMER_BALL: + return "tb"; + case PokeballType.PREMIER_BALL: + return "preb"; + case PokeballType.REPEAT_BALL: + return "repb"; + case PokeballType.SAFARI_BALL: + return "sb"; + default: + console.error("Missing ball atlas key"); + return "pb"; } } @@ -43,6 +56,25 @@ export function getPokeballName(type: PokeballType): string { case PokeballType.LUXURY_BALL: ret = i18next.t("pokeball:luxuryBall"); break; + case PokeballType.QUICK_BALL: + ret = i18next.t("pokeball:quickBall"); + break; + case PokeballType.TIMER_BALL: + ret = i18next.t("pokeball:timerBall"); + break; + case PokeballType.PREMIER_BALL: + ret = i18next.t("pokeball:premierBall"); + break; + case PokeballType.REPEAT_BALL: + ret = i18next.t("pokeball:repeatBall"); + break; + case PokeballType.SAFARI_BALL: + ret = i18next.t("pokeball:safariBall"); + break; + + default: + console.error("Missing ball language translation description"); + ret = i18next.t("pokeball:pokeBall"); } return ret; } @@ -61,6 +93,24 @@ export function getPokeballCatchMultiplier(type: PokeballType): number { return -1; case PokeballType.LUXURY_BALL: return 1; + + case PokeballType.QUICK_BALL: + return globalScene.currentBattle.turn == 1 ? 5 : 1; + case PokeballType.TIMER_BALL: + return globalScene.currentBattle.turn > 11 ? 4 : 1 + ((globalScene.currentBattle.turn-1) * 0.3); + case PokeballType.PREMIER_BALL: + return globalScene.premierPokeballMultiplier; + case PokeballType.REPEAT_BALL: + if (globalScene.getEnemyPokemon()){ + return globalScene.gameData.dexData[globalScene.getEnemyPokemon().species.speciesId].caughtAttr ? 3.5 : 1; + } + return 1 + case PokeballType.SAFARI_BALL: + return 1.5 + + default: + console.error("Missing ball catch multiplier"); + return 1; } } @@ -78,6 +128,21 @@ export function getPokeballTintColor(type: PokeballType): number { return 0xa441bd; case PokeballType.LUXURY_BALL: return 0xffde6a; + case PokeballType.QUICK_BALL: + return 0xd52929; + case PokeballType.TIMER_BALL: + return 0xd52929; + case PokeballType.PREMIER_BALL: + return 0xd52929; + case PokeballType.REPEAT_BALL: + return 0xd52929; + case PokeballType.TIMER_BALL: + return 0xd52929; + case PokeballType.SAFARI_BALL: + return 0xd52929; + default: + console.error("Missing ball tint color"); + return 0xd52929; } } diff --git a/src/enums/pokeball.ts b/src/enums/pokeball.ts index 8d97fea464c..148c7708828 100644 --- a/src/enums/pokeball.ts +++ b/src/enums/pokeball.ts @@ -5,4 +5,10 @@ export enum PokeballType { ROGUE_BALL, MASTER_BALL, LUXURY_BALL, + QUICK_BALL, + TIMER_BALL, + PREMIER_BALL, + REPEAT_BALL, + CRITICAL_BALL, // Not implemented + SAFARI_BALL // Do not put anything above this ball } diff --git a/src/field/anims.ts b/src/field/anims.ts index 82aa7b7e894..b3ff0a3d457 100644 --- a/src/field/anims.ts +++ b/src/field/anims.ts @@ -20,6 +20,28 @@ export function addPokeballOpenParticles(x: number, y: number, pokeballType: Pok case PokeballType.MASTER_BALL: doMbOpenParticles(x, y); break; + case PokeballType.LUXURY_BALL: + doMbOpenParticles(x, y); + break; + case PokeballType.QUICK_BALL: + doMbOpenParticles(x, y); + break; + case PokeballType.TIMER_BALL: + doMbOpenParticles(x, y); + break; + case PokeballType.PREMIER_BALL: + doMbOpenParticles(x, y); + break; + case PokeballType.REPEAT_BALL: + doMbOpenParticles(x, y); + break; + case PokeballType.SAFARI_BALL: + doMbOpenParticles(x, y); + break; + default: + doDefaultPbOpenParticles(x, y, 48); + console.log("Missing pokeball animation.") + break; } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7cd0b9fecf8..cf757aec858 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5957,8 +5957,7 @@ export class PlayerPokemon extends Pokemon { const amount = new NumberHolder(friendship); globalScene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount); friendship = amount.value; - - const newFriendship = this.friendship + friendship; + const newFriendship = this.friendship + (this.pokeball === PokeballType.LUXURY_BALL ? friendship * 2 : friendship); // If capped is true, only adjust friendship if the new friendship is less than or equal to 200. if (!capped || newFriendship <= RARE_CANDY_FRIENDSHIP_CAP) { this.friendship = Math.min(newFriendship, 255); diff --git a/src/modifier/init-modifier-pools.ts b/src/modifier/init-modifier-pools.ts index 3e180846183..ddca565590e 100644 --- a/src/modifier/init-modifier-pools.ts +++ b/src/modifier/init-modifier-pools.ts @@ -145,6 +145,8 @@ function initCommonModifierPool() { function initGreatModifierPool() { modifierPool[ModifierTier.GREAT] = [ new WeightedModifierType(modifierTypes.GREAT_BALL, () => (hasMaximumBalls(PokeballType.GREAT_BALL) ? 0 : 6), 6), + new WeightedModifierType(modifierTypes.PREMIER_BALL, () => (hasMaximumBalls(PokeballType.PREMIER_BALL) ? 0 : 6), 6), + new WeightedModifierType(modifierTypes.LUXURY_BALL, () => (hasMaximumBalls(PokeballType.LUXURY_BALL) ? 0 : 6), 6), new WeightedModifierType(modifierTypes.PP_UP, 2), new WeightedModifierType( modifierTypes.FULL_HEAL, @@ -348,6 +350,8 @@ function initGreatModifierPool() { function initUltraModifierPool() { modifierPool[ModifierTier.ULTRA] = [ new WeightedModifierType(modifierTypes.ULTRA_BALL, () => (hasMaximumBalls(PokeballType.ULTRA_BALL) ? 0 : 15), 15), + new WeightedModifierType(modifierTypes.REPEAT_BALL, () => (hasMaximumBalls(PokeballType.REPEAT_BALL) ? 0 : 15), 15), + new WeightedModifierType(modifierTypes.TIMER_BALL, () => (hasMaximumBalls(PokeballType.TIMER_BALL) ? 0 : 15), 15), new WeightedModifierType(modifierTypes.MAX_LURE, lureWeightFunc(30, 4)), new WeightedModifierType(modifierTypes.BIG_NUGGET, skipInLastClassicWaveOrDefault(12)), new WeightedModifierType(modifierTypes.PP_MAX, 3), @@ -572,6 +576,7 @@ function initUltraModifierPool() { function initRogueModifierPool() { modifierPool[ModifierTier.ROGUE] = [ new WeightedModifierType(modifierTypes.ROGUE_BALL, () => (hasMaximumBalls(PokeballType.ROGUE_BALL) ? 0 : 16), 16), + new WeightedModifierType(modifierTypes.QUICK_BALL, () => (hasMaximumBalls(PokeballType.QUICK_BALL) ? 0 : 16), 16), new WeightedModifierType(modifierTypes.RELIC_GOLD, skipInLastClassicWaveOrDefault(2)), new WeightedModifierType(modifierTypes.LEFTOVERS, 3), new WeightedModifierType(modifierTypes.SHELL_BELL, 3), diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 8b77900cb62..cf1ec69b0d0 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1837,6 +1837,11 @@ const modifierTypeInitObj = Object.freeze({ ULTRA_BALL: () => new AddPokeballModifierType("ub", PokeballType.ULTRA_BALL, 5), ROGUE_BALL: () => new AddPokeballModifierType("rb", PokeballType.ROGUE_BALL, 5), MASTER_BALL: () => new AddPokeballModifierType("mb", PokeballType.MASTER_BALL, 1), + LUXURY_BALL: () => new AddPokeballModifierType("lb", PokeballType.LUXURY_BALL, 5), + QUICK_BALL: () => new AddPokeballModifierType("qb", PokeballType.QUICK_BALL, 3), + TIMER_BALL: () => new AddPokeballModifierType("tb", PokeballType.TIMER_BALL, 5), + PREMIER_BALL: () => new AddPokeballModifierType("preb", PokeballType.PREMIER_BALL, 5), + REPEAT_BALL: () => new AddPokeballModifierType("repb", PokeballType.REPEAT_BALL, 3), RARE_CANDY: () => new PokemonLevelIncrementModifierType("modifierType:ModifierType.RARE_CANDY", "rare_candy"), RARER_CANDY: () => new AllPokemonLevelIncrementModifierType("modifierType:ModifierType.RARER_CANDY", "rarer_candy"), diff --git a/src/overrides.ts b/src/overrides.ts index b8212ea8fd6..0d5844992cb 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -105,6 +105,11 @@ class DefaultOverrides { [PokeballType.ULTRA_BALL]: 0, [PokeballType.ROGUE_BALL]: 0, [PokeballType.MASTER_BALL]: 0, + [PokeballType.LUXURY_BALL]: 0, + [PokeballType.QUICK_BALL]: 0, + [PokeballType.TIMER_BALL]: 0, + [PokeballType.PREMIER_BALL]: 0, + [PokeballType.REPEAT_BALL]: 0, }, }; /** Forces an item to be UNLOCKED */ diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 699caa2af21..894bd59d319 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -13,7 +13,7 @@ import { import { getStatusEffectCatchRateMultiplier } from "#data/status-effect"; import { BattlerIndex } from "#enums/battler-index"; import { ChallengeType } from "#enums/challenge-type"; -import type { PokeballType } from "#enums/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { StatusEffect } from "#enums/status-effect"; import { UiMode } from "#enums/ui-mode"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "#field/anims"; @@ -56,6 +56,16 @@ export class AttemptCapturePhase extends PokemonPhase { } globalScene.pokeballCounts[this.pokeballType]--; + if (globalScene.lastPokeballType != this.pokeballType){ + globalScene.lastPokeballType = this.pokeballType; + globalScene.premierPokeballMultiplier = 1 + }else if (globalScene.lastPokeballType == PokeballType.PREMIER_BALL && PokeballType.PREMIER_BALL == this.pokeballType){ + if (globalScene.premierPokeballMultiplier < 5){ + globalScene.premierPokeballMultiplier += 0.5 + }else{ + globalScene.premierPokeballMultiplier = 5 + } + } this.originalY = pokemon.y; @@ -63,6 +73,7 @@ export class AttemptCapturePhase extends PokemonPhase { const _2h = 2 * pokemon.hp; const catchRate = pokemon.species.catchRate; const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); + console.log(pokeballMultiplier); const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; const modifiedCatchRate = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); const shakeProbability = Math.round(65536 / Math.pow(255 / modifiedCatchRate, 0.1875)); // Formula taken from gen 6 diff --git a/src/phases/command-phase.ts b/src/phases/command-phase.ts index 37e07c6c282..bba7e6239ff 100644 --- a/src/phases/command-phase.ts +++ b/src/phases/command-phase.ts @@ -454,7 +454,7 @@ export class CommandPhase extends FieldPhase { const isChallengeActive = globalScene.gameMode.hasAnyChallenges(); const isFinalBoss = globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex); - const numBallTypes = 5; + const numBallTypes = 10; if (cursor < numBallTypes) { const targetPokemon = globalScene.getEnemyPokemon(false); if ( @@ -467,13 +467,13 @@ export class CommandPhase extends FieldPhase { // The message is customized for the final boss. if ( isFinalBoss && - (cursor < PokeballType.MASTER_BALL || (cursor === PokeballType.MASTER_BALL && isChallengeActive)) + (cursor !== PokeballType.MASTER_BALL || (cursor === PokeballType.MASTER_BALL && isChallengeActive)) ) { this.queueShowText("battle:noPokeballForceFinalBossCatchable"); return false; } // When facing any other boss, Master Ball can always be used, and we use the standard message. - if (cursor < PokeballType.MASTER_BALL) { + if (cursor !== PokeballType.MASTER_BALL) { this.queueShowText("battle:noPokeballStrong"); return false; } diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 72ae59faaec..61c71c89649 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -14,6 +14,7 @@ import { SettingsKeyboardUiHandler } from "#ui/settings-keyboard-ui-handler"; import { SettingsUiHandler } from "#ui/settings-ui-handler"; import { StarterSelectUiHandler } from "#ui/starter-select-ui-handler"; import Phaser from "phaser"; +import { CommandUiHandler } from "#ui/command-ui-handler"; type ActionKeys = Record void>; @@ -213,6 +214,7 @@ export class UiInputs { SettingsAudioUiHandler, SettingsGamepadUiHandler, SettingsKeyboardUiHandler, + CommandUiHandler, ]; const uiHandler = globalScene.ui?.getHandler(); if (whitelist.some(handler => uiHandler instanceof handler)) { diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index 3d8efca96b8..1f624f7d035 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -14,6 +14,8 @@ export class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; private pokeballSelectBg: Phaser.GameObjects.NineSlice; private countsText: Phaser.GameObjects.Text; + private optionsText: Phaser.GameObjects.Text; + private cursorOffSet: number = 0; private cursorObj: Phaser.GameObjects.Image | null; @@ -30,12 +32,12 @@ export class BallUiHandler extends UiHandler { let optionsTextContent = ""; - for (let pb = 0; pb < Object.keys(globalScene.pokeballCounts).length; pb++) { + for (let pb = 0; pb < 6; pb++) { optionsTextContent += `${getPokeballName(pb)}\n`; } optionsTextContent += i18next.t("commandUiHandler:ballCancel"); - const optionsText = addTextObject(0, 0, optionsTextContent, TextStyle.WINDOW, { align: "right", maxLines: 6 }); - const optionsTextWidth = optionsText.displayWidth; + this.optionsText = addTextObject(0, 0, optionsTextContent, TextStyle.WINDOW, { align: "right", maxLines: 6 }); + const optionsTextWidth = this.optionsText.displayWidth; this.pokeballSelectContainer = globalScene.add.container( globalScene.scaledCanvas.width - 51 - Math.max(64, optionsTextWidth), -49, @@ -46,18 +48,17 @@ export class BallUiHandler extends UiHandler { this.pokeballSelectBg = addWindow(0, 0, 50 + Math.max(64, optionsTextWidth), 32 + 480 * this.scale); this.pokeballSelectBg.setOrigin(0, 1); this.pokeballSelectContainer.add(this.pokeballSelectBg); - this.pokeballSelectContainer.add(optionsText); - optionsText.setOrigin(0, 0); - optionsText.setPositionRelative(this.pokeballSelectBg, 42, 9); - optionsText.setLineSpacing(this.scale * 72); + this.pokeballSelectContainer.add(this.optionsText); + this.optionsText.setOrigin(0, 0); + this.optionsText.setPositionRelative(this.pokeballSelectBg, 42, 9); + this.optionsText.setLineSpacing(this.scale * 72); this.countsText = addTextObject(0, 0, "", TextStyle.WINDOW, { - maxLines: 5, + maxLines: 6, }); this.countsText.setPositionRelative(this.pokeballSelectBg, 18, 9); this.countsText.setLineSpacing(this.scale * 72); this.pokeballSelectContainer.add(this.countsText); - this.setCursor(0); } @@ -116,11 +117,27 @@ export class BallUiHandler extends UiHandler { updateCounts() { this.countsText.setText( Object.values(globalScene.pokeballCounts) + .slice(this.cursorOffSet) .map(c => `×${c}`) .join("\n"), ); } + updatePokeballs() { + let optionsTextContent = ""; + let totalDisplayed = Object.keys(globalScene.pokeballCounts).length - this.cursorOffSet > 5 ? 6 : 5; + + for (let pb = 0; pb < totalDisplayed; pb++) { + optionsTextContent += `${getPokeballName(pb + this.cursorOffSet)}\n`; + } + if (totalDisplayed == 5){ + optionsTextContent += i18next.t("commandUiHandler:ballCancel"); + } + this.optionsText.setText( + optionsTextContent + ); + } + setCursor(cursor: number): boolean { const ret = super.setCursor(cursor); @@ -128,10 +145,16 @@ export class BallUiHandler extends UiHandler { this.cursorObj = globalScene.add.image(0, 0, "cursor"); this.pokeballSelectContainer.add(this.cursorObj); } - + if (this.cursor > this.cursorOffSet + 5){ + this.cursorOffSet = this.cursor - 5 + } + else if (this.cursor < this.cursorOffSet){ + this.cursorOffSet = this.cursor; + } this.cursorObj.setScale(this.scale * 6); - this.cursorObj.setPositionRelative(this.pokeballSelectBg, 12, 15 + (6 + this.cursor * 96) * this.scale); - + this.cursorObj.setPositionRelative(this.pokeballSelectBg, 12, 15 + (6 + (this.cursor - this.cursorOffSet) * 96) * this.scale); + this.updateCounts(); + this.updatePokeballs(); return ret; } diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index b702bcd0803..0911953eaf7 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -117,7 +117,6 @@ export class CommandUiHandler extends UiHandler { let success = false; const cursor = this.getCursor(); - if (button === Button.CANCEL || button === Button.ACTION) { if (button === Button.ACTION) { switch (cursor) { @@ -187,6 +186,18 @@ export class CommandUiHandler extends UiHandler { this.toggleTeraButton(); } break; + case Button.CYCLE_SHINY: + const commandPhase = globalScene.phaseManager.getCurrentPhase() as CommandPhase; + if (globalScene.pokeballCounts[globalScene.lastPokeballType]) { + if (commandPhase.handleCommand(Command.BALL, globalScene.lastPokeballType)) { + globalScene.ui.setMode(UiMode.COMMAND, commandPhase.getFieldIndex()); + globalScene.ui.setMode(UiMode.MESSAGE); + success = true; + } + } else { + ui.playError(); + } + break } }