diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index fa0da5a15ac..1e271a719f8 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -49,8 +49,9 @@ export function getPokeballName(type: PokeballType): string { return ret; } -export function getPokeballCatchMultiplier(type: PokeballType, enemyPokemon?: Pokemon): number { +export function getPokeballCatchMultiplier(type: PokeballType, enemyPokemon?: Pokemon, getBoostedDescription?: boolean): number { const pokemon = enemyPokemon ?? null; + const description = getBoostedDescription ?? false; switch (type) { case PokeballType.POKEBALL: return 1; @@ -59,7 +60,12 @@ export function getPokeballCatchMultiplier(type: PokeballType, enemyPokemon?: Po case PokeballType.ULTRA_BALL: return 2; case PokeballType.ROGUE_BALL: - console.log(pokemon); + /* making rogue balls have a higher chance to catch pokemon if they have a tinted pokeball (i.e. at least one thing is new for them) + * you can also get the boosted type for a description (i.e. for modifier-type) + */ + if (pokemon?.isTintedPokeball() || description) { + return 5; + } return 3; case PokeballType.MASTER_BALL: return -1; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 269d0b1dba5..08efef30a6e 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -28,7 +28,7 @@ import PartyUiHandler, { PartyOption, PartyUiMode } from "../ui/party-ui-handler import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import { LevelMoves } from "../data/pokemon-level-moves"; import { DamageAchv, achvs } from "../system/achv"; -import { DexAttr, StarterDataEntry, StarterMoveset } from "../system/game-data"; +import { AbilityAttr, DexAttr, StarterDataEntry, StarterMoveset } from "../system/game-data"; import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities"; import { Nature, getNatureStatMultiplier } from "../data/nature"; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from "../data/pokemon-forms"; @@ -3498,6 +3498,37 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const rootForm = getPokemonSpecies(this.species.getRootSpeciesId()); return rootForm.getAbility(abilityIndex) === rootForm.getAbility(currentAbilityIndex); } + + /* Checks whether or not the pokemon's pokeball will be tinted. + * This checks the dex attributes (gender, shiny/non shiny, variant and forms) + * These values are checked against the exact pokemon you're catching (i.e. catching charizard won't compare against charmander) + * It also checks your abilities against the starter version + * If any are "new", the pokemon's pokeball is tinted + * @returns true if the pokemon's pokeball should be tinted, meaning at least one thing is new + */ + isTintedPokeball(): boolean { + const dexEntry = this.scene.gameData.dexData[this.species.speciesId]; + const opponentPokemonDexAttr = this.getDexAttr(); + + // Check if Player owns all genders and forms of the Pokemon + const missingDexAttrs = ((dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr); + + const ownedAbilityAttrs = this.scene.gameData.starterData[this.species.getRootSpeciesId()].abilityAttr; + + let playerOwnsThisAbility = false; + // Check if the player owns ability for the root form + if ((ownedAbilityAttrs & AbilityAttr.ABILITY_1) > 0 && this.hasSameAbilityInRootForm(0)) { + playerOwnsThisAbility = true; + } + if ((ownedAbilityAttrs & AbilityAttr.ABILITY_2) > 0 && this.hasSameAbilityInRootForm(1)) { + playerOwnsThisAbility = true; + } + if ((ownedAbilityAttrs & AbilityAttr.ABILITY_HIDDEN) > 0 && this.hasSameAbilityInRootForm(2)) { + playerOwnsThisAbility = true; + } + + return (missingDexAttrs || !playerOwnsThisAbility); + } } export default interface Pokemon { diff --git a/src/locales/en/modifier-type.json b/src/locales/en/modifier-type.json index f73a3dcccae..d362ab1e69d 100644 --- a/src/locales/en/modifier-type.json +++ b/src/locales/en/modifier-type.json @@ -2,7 +2,8 @@ "ModifierType": { "AddPokeballModifierType": { "name": "{{modifierCount}}x {{pokeballName}}", - "description": "Receive {{pokeballName}} x{{modifierCount}} (Inventory: {{pokeballAmount}}) \nCatch Rate: {{catchRate}}" + "description": "Receive {{pokeballName}} x{{modifierCount}} (Inventory: {{pokeballAmount}}) \nCatch Rate: {{catchRate}}", + "catchRateGenerator": "{{normalCatchRate}}x ({{boostedCatchRate}}x for uncaught Pokemon)" }, "AddVoucherModifierType": { "name": "{{modifierCount}}x {{voucherTypeName}}", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index fe586074c79..42183148b85 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -181,10 +181,19 @@ class AddPokeballModifierType extends ModifierType { } getDescription(scene: BattleScene): string { + let catchRate: String; + if (this.pokeballType === PokeballType.ROGUE_BALL) { + catchRate = i18next.t("modifierType:ModifierType.AddPokeballModifierType.catchRateGenerator", { + "normalCatchRate": getPokeballCatchMultiplier(this.pokeballType), + "boostedCatchRate": getPokeballCatchMultiplier(this.pokeballType, null, true), + }); + } else if (this.pokeballType !== PokeballType.MASTER_BALL) { + catchRate = `${getPokeballCatchMultiplier(this.pokeballType)}x`; + } return i18next.t("modifierType:ModifierType.AddPokeballModifierType.description", { "modifierCount": this.count, "pokeballName": getPokeballName(this.pokeballType), - "catchRate": getPokeballCatchMultiplier(this.pokeballType) > -1 ? `${getPokeballCatchMultiplier(this.pokeballType)}x` : "100%", + "catchRate": catchRate, "pokeballAmount": `${scene.pokeballCounts[this.pokeballType]}`, }); } diff --git a/src/phases/attempt-capture-phase.ts b/src/phases/attempt-capture-phase.ts index 72995c0f006..c78e90c89d2 100644 --- a/src/phases/attempt-capture-phase.ts +++ b/src/phases/attempt-capture-phase.ts @@ -43,7 +43,7 @@ export class AttemptCapturePhase extends PokemonPhase { const _3m = 3 * pokemon.getMaxHp(); const _2h = 2 * pokemon.hp; const catchRate = pokemon.species.catchRate; - const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType); + const pokeballMultiplier = getPokeballCatchMultiplier(this.pokeballType, pokemon); const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1; const x = Math.round((((_3m - _2h) * catchRate * pokeballMultiplier) / _3m) * statusMultiplier); const y = Math.round(65536 / Math.sqrt(Math.sqrt(255 / x))); diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 05c634609f8..7eef0ea54a5 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -366,31 +366,13 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const dexEntry = pokemon.scene.gameData.dexData[pokemon.species.speciesId]; this.ownedIcon.setVisible(!!dexEntry.caughtAttr); - const opponentPokemonDexAttr = pokemon.getDexAttr(); if (pokemon.scene.gameMode.isClassic) { if (pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0) { this.championRibbon.setVisible(true); } } - // Check if Player owns all genders and forms of the Pokemon - const missingDexAttrs = ((dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr); - - const ownedAbilityAttrs = pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()].abilityAttr; - - let playerOwnsThisAbility = false; - // Check if the player owns ability for the root form - if ((ownedAbilityAttrs & 1) > 0 && pokemon.hasSameAbilityInRootForm(0)) { - playerOwnsThisAbility = true; - } - if ((ownedAbilityAttrs & 2) > 0 && pokemon.hasSameAbilityInRootForm(1)) { - playerOwnsThisAbility = true; - } - if ((ownedAbilityAttrs & 4) > 0 && pokemon.hasSameAbilityInRootForm(2)) { - playerOwnsThisAbility = true; - } - - if (missingDexAttrs || !playerOwnsThisAbility) { + if (pokemon.isTintedPokeball()) { this.ownedIcon.setTint(0x808080); }