diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 8878f6fad..71ebed2b6 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -5,7 +5,7 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMov import { Mode } from './ui/ui'; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; -import { BerryModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HeldItemTransferModifier, HitHealModifier, MapModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier } from "./modifier/modifier"; +import { BerryModifier, ContactHeldItemTransferChanceModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HeldItemTransferModifier, HitHealModifier, MapModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier } from "./modifier/modifier"; import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler"; import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballName, getPokeballTintColor, PokeballType } from "./data/pokeball"; import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims"; @@ -767,7 +767,7 @@ export class TurnEndPhase extends FieldPhase { this.executeForBoth((pokemon: Pokemon) => applyPostTurnAbAttrs(PostTurnAbAttr, pokemon)); - this.scene.applyModifiers(HeldItemTransferModifier, pokemon.isPlayer(), pokemon); + this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon); pokemon.battleSummonData.turnCount++; }; @@ -1049,6 +1049,8 @@ abstract class MoveEffectPhase extends PokemonPhase { applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveHitEffectAttr && (!!target.hp || (attr as MoveHitEffectAttr).selfTarget), user, target, this.move.getMove()); if (target.hp) applyPostDefendAbAttrs(PostDefendAbAttr, user, target, this.move, result); + if (this.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) + this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user); } } this.end(); diff --git a/src/data/biome.ts b/src/data/biome.ts index 225dc945d..8579879bb 100644 --- a/src/data/biome.ts +++ b/src/data/biome.ts @@ -671,7 +671,7 @@ export const biomePools: BiomePools = { { 1: [ Species.BALTOY ], 36: [ Species.CLAYDOL ] }, { 1: [ Species.ELGYEM ], 42: [ Species.BEHEEYEM ] } ], - [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, { 1: [ Species.BRONZOR ], 33: [ Species.BRONZONG ] }, Species.SIGILYPH, { 1: [ Species.KLINK ], 38: [ Species.KLANG ], 49: [ Species.KLINKLANG ] } ], + [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, { 1: [ Species.BRONZOR ], 33: [ Species.BRONZONG ] }, Species.SIGILYPH ], [BiomePoolTier.RARE]: [ Species.MR_MIME, Species.WOBBUFFET, { 1: [ Species.GOTHITA ], 32: [ Species.GOTHORITA ], 41: [ Species.GOTHITELLE ] } ], [BiomePoolTier.SUPER_RARE]: [ Species.ESPEON, { 1: [ Species.ARCHEN ], 37: [ Species.ARCHEOPS ] } ], [BiomePoolTier.ULTRA_RARE]: [ Species.MEW, Species.VICTINI ], @@ -3582,19 +3582,16 @@ export const biomePools: BiomePools = { ] ], [ Species.KLINK, Type.STEEL, -1, [ - [ Biome.FACTORY, BiomePoolTier.COMMON ], - [ Biome.RUINS, BiomePoolTier.UNCOMMON ] + [ Biome.FACTORY, BiomePoolTier.COMMON ] ] ], [ Species.KLANG, Type.STEEL, -1, [ - [ Biome.FACTORY, BiomePoolTier.COMMON ], - [ Biome.RUINS, BiomePoolTier.UNCOMMON ] + [ Biome.FACTORY, BiomePoolTier.COMMON ] ] ], [ Species.KLINKLANG, Type.STEEL, -1, [ [ Biome.FACTORY, BiomePoolTier.COMMON ], - [ Biome.FACTORY, BiomePoolTier.BOSS ], - [ Biome.RUINS, BiomePoolTier.UNCOMMON ] + [ Biome.FACTORY, BiomePoolTier.BOSS ] ] ], [ Species.TYNAMO, Type.ELECTRIC, -1, [ diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 1cfd049bf..e759f13e9 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -267,11 +267,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm { if (noEvolutionChance === 1 || Math.random() < noEvolutionChance) return this.speciesId; - - if (evolutionPool.size === 1) - return evolutionPool.values()[0]; - - const randValue = Math.random() * totalWeight; + + const randValue = evolutionPool.size === 1 ? 0 : Math.random() * totalWeight; for (let weight of evolutionPool.keys()) { if (randValue < weight) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index b1f566016..e481d1e47 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -492,9 +492,15 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator { } } -class HeldItemTransferModifierType extends PokemonHeldItemModifierType { +export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemModifierType { + constructor(name: string, chancePercent: integer, iconImage?: string, group?: string, soundName?: string) { + super(name, `On contact, there is a ${chancePercent}% chance the foe's held item will be stolen`, (type, args) => new Modifiers.ContactHeldItemTransferChanceModifier(type, (args[0] as Pokemon).id, chancePercent), iconImage, group, soundName); + } +} + +export class TurnHeldItemTransferModifierType extends PokemonHeldItemModifierType { constructor(name: string, iconImage?: string, group?: string, soundName?: string) { - super(name, 'Every turn, the holder acquires one held item from the foe POKéMON', (type, args) => new Modifiers.HeldItemTransferModifier(type, (args[0] as Pokemon).id), iconImage, group, soundName); + super(name, 'Every turn, the holder acquires one held item from the foe', (type, args) => new Modifiers.TurnHeldItemTransferModifier(type, (args[0] as Pokemon).id), iconImage, group, soundName); } } @@ -598,6 +604,8 @@ const modifierTypes = { LUCKY_EGG: () => new PokemonExpBoosterModifierType('LUCKY EGG', 50), GOLDEN_EGG: () => new PokemonExpBoosterModifierType('GOLDEN EGG', 200), + GRIP_CLAW: () => new ContactHeldItemTransferChanceModifierType('GRIP CLAW', 10), + HEALING_CHARM: () => new ModifierType('HEALING CHARM', 'Doubles the effectiveness of HP restoring moves and items (excludes revives)', (type, _args) => new Modifiers.HealingBoosterModifier(type, 2), 'healing_charm'), CANDY_JAR: () => new ModifierType('CANDY JAR', 'Increases the number of levels added by RARE CANDY items by 1', (type, _args) => new Modifiers.LevelIncrementBoosterModifier(type)), @@ -621,7 +629,7 @@ const modifierTypes = { SHINY_CHARM: () => new ModifierType('SHINY CHARM', 'Dramatically increases the chance of a wild POKéMON being shiny', (type, _args) => new Modifiers.ShinyRateBoosterModifier(type)), - MINI_BLACK_HOLE: () => new HeldItemTransferModifierType('MINI BLACK HOLE'), + MINI_BLACK_HOLE: () => new TurnHeldItemTransferModifierType('MINI BLACK HOLE'), GOLDEN_POKEBALL: () => new ModifierType(`GOLDEN ${getPokeballName(PokeballType.POKEBALL)}`, 'Adds 1 extra item option at the end of every battle', (type, _args) => new Modifiers.ExtraModifierModifier(type), 'pb_gold', null, 'pb_bounce_1'), @@ -697,6 +705,7 @@ const modifierPool = { new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 4), new WeightedModifierType(modifierTypes.TM_ULTRA, 5), new WeightedModifierType(modifierTypes.CANDY_JAR, 3), + new WeightedModifierType(modifierTypes.GRIP_CLAW, 2), new WeightedModifierType(modifierTypes.HEALING_CHARM, 1), new WeightedModifierType(modifierTypes.BATON, 1), new WeightedModifierType(modifierTypes.FOCUS_BAND, 3), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 9769f79d1..4d4ad907a 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -255,7 +255,7 @@ export class MapModifier extends PersistentModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 1; } } @@ -426,7 +426,7 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 5; } } @@ -457,7 +457,7 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 3; } } @@ -486,7 +486,7 @@ export class TurnHealModifier extends PokemonHeldItemModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 4; } } @@ -515,7 +515,7 @@ export class HitHealModifier extends PokemonHeldItemModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 4; } } @@ -609,7 +609,7 @@ export class PreserveBerryModifier extends PersistentModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 4; } } @@ -832,7 +832,7 @@ export class HealingBoosterModifier extends PersistentModifier { return true; } - getMaxStackCount(): number { + getmaxStackCount(): integer { return 4; } } @@ -994,30 +994,26 @@ export class SwitchEffectTransferModifier extends PokemonHeldItemModifier { } } -export class HeldItemTransferModifier extends PokemonHeldItemModifier { +export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { super(type, pokemonId, stackCount); } - matchType(modifier: Modifier): boolean { - return modifier instanceof HeldItemTransferModifier; - } - - clone(): HeldItemTransferModifier { - return new HeldItemTransferModifier(this.type, this.pokemonId, this.stackCount); - } - apply(args: any[]): boolean { const pokemon = args[0] as Pokemon; const targetPokemon = pokemon.getOpponent(); if (!targetPokemon) return false; + const transferredItemCount = this.getTransferredItemCount(); + if (!transferredItemCount) + return false; + const transferredModifierTypes: ModifierTypes.ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && !m.matchType(this), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; - for (let i = 0; i < this.getStackCount(); i++) { + for (let i = 0; i < transferredItemCount; i++) { if (!itemModifiers.length) break; const randItemIndex = Utils.randInt(itemModifiers.length); @@ -1029,10 +1025,74 @@ export class HeldItemTransferModifier extends PokemonHeldItemModifier { } for (let mt of transferredModifierTypes) - pokemon.scene.queueMessage(getPokemonMessage(targetPokemon, `'s ${mt.name} was absorbed\nby ${pokemon.name}'s MINI BLACK HOLE!`)); + pokemon.scene.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt)); return !!transferredModifierTypes.length; } + + abstract getTransferredItemCount(): integer + + abstract getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string +} + +export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { + constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + super(type, pokemonId, stackCount); + } + + matchType(modifier: Modifier): boolean { + return modifier instanceof TurnHeldItemTransferModifier; + } + + clone(): TurnHeldItemTransferModifier { + return new TurnHeldItemTransferModifier(this.type, this.pokemonId, this.stackCount); + } + + getTransferredItemCount(): integer { + return this.getStackCount(); + } + + getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { + return getPokemonMessage(targetPokemon, `'s ${item.name} was absorbed\nby ${pokemon.name}'s ${this.type.name}!`); + } + + getMaxStackCount(): integer { + return 3; + } +} + +export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModifier { + private chance: number; + + constructor(type: ModifierType, pokemonId: integer, chancePercent: integer, stackCount?: integer) { + super(type, pokemonId, stackCount); + + this.chance = chancePercent / 100; + } + + matchType(modifier: Modifier): boolean { + return modifier instanceof ContactHeldItemTransferChanceModifier; + } + + clone(): ContactHeldItemTransferChanceModifier { + return new ContactHeldItemTransferChanceModifier(this.type, this.pokemonId, this.chance * 100, this.stackCount); + } + + getArgs(): any[] { + return super.getArgs().concat(this.chance * 100); + } + + getTransferredItemCount(): integer { + return Math.random() < (this.chance * this.getStackCount()) ? 1 : 0; + } + + getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { + return getPokemonMessage(targetPokemon, `'s ${item.name} was snatched\nby ${pokemon.name}'s ${this.type.name}!`); + } + + getmaxStackCount(): integer { + return 5; + } } export class ExtraModifierModifier extends PersistentModifier {