#=============================================================================== # Instances of this class are individual Pokémon. # The player's party Pokémon are stored in the array $Trainer.party. #=============================================================================== class Pokemon # @return [Integer] this Pokémon's national Pokédex number attr_reader :species # If defined, this Pokémon's form will be this value even if a MultipleForms # handler tries to say otherwise. # @return [Integer, nil] this Pokémon's form attr_accessor :forced_form # If defined, is the time (in Integer form) when this Pokémon's form was set. # @return [Integer, nil] the time this Pokémon's form was set attr_accessor :time_form_set # @return [Integer] the current experience points attr_reader :exp # @return [Integer] the number of steps until this Pokémon hatches, 0 if this Pokémon is not an egg attr_accessor :steps_to_hatch # @return [Integer] the current HP attr_reader :hp # @return [Integer] this Pokémon's current status (from PBStatuses) attr_reader :status # @return [Integer] sleep count / toxic flag / 0: # sleep (number of rounds before waking up), toxic (0 = regular poison, 1 = toxic) attr_accessor :statusCount # This Pokémon's shininess (true, false, nil). Is recalculated if made nil. # @param value [Boolean, nil] whether this Pokémon is shiny attr_writer :shiny # The index of this Pokémon's ability (0, 1 are natural abilities, 2+ are # hidden abilities)as defined for its species/form. An ability may not be # defined at this index. Is recalculated (as 0 or 1) if made nil. # @param value [Integer, nil] forced ability index (nil if none is set) attr_writer :ability_index # @return [Array] the moves known by this Pokémon attr_accessor :moves # @return [Array] the IDs of moves known by this Pokémon when it was obtained attr_accessor :first_moves # @return [Array] an array of ribbons owned by this Pokémon attr_accessor :ribbons # @return [Integer] contest stats attr_accessor :cool, :beauty, :cute, :smart, :tough, :sheen # @return [Integer] the Pokérus strain and infection time attr_accessor :pokerus # @return [Integer] this Pokémon's current happiness (an integer between 0 and 255) attr_accessor :happiness # @return [Symbol] the item ID of the Poké Ball this Pokémon is in attr_accessor :poke_ball # @return [Integer] this Pokémon's markings, one bit per marking attr_accessor :markings # @return [Array] an array of IV values for HP, Atk, Def, Speed, Sp. Atk and Sp. Def attr_accessor :iv # An array of booleans indicating whether a stat is made to have maximum IVs # (for Hyper Training). Set like @ivMaxed[PBStats::ATTACK] = true # @return [Array] an array of booleans that max each IV value attr_accessor :ivMaxed # @return [Array] this Pokémon's effort values attr_accessor :ev # @return [Integer] calculated stats attr_reader :totalhp, :attack, :defense, :spatk, :spdef, :speed # @return [Owner] this Pokémon's owner attr_reader :owner # @return [Integer] the manner this Pokémon was obtained: # 0 (met), 1 (as egg), 2 (traded), 4 (fateful encounter) attr_accessor :obtain_method # @return [Integer] the ID of the map this Pokémon was obtained in attr_accessor :obtain_map # Describes the manner this Pokémon was obtained. If left undefined, # the obtain map's name is used. # @return [String] the obtain text attr_accessor :obtain_text # @return [Integer] the level of this Pokémon when it was obtained attr_accessor :obtain_level # If this Pokémon hatched from an egg, returns the map ID where the hatching happened. # Otherwise returns 0. # @return [Integer] the map ID where egg was hatched (0 by default) attr_accessor :hatched_map # Another Pokémon which has been fused with this Pokémon (or nil if there is none). # Currently only used by Kyurem, to record a fused Reshiram or Zekrom. # @return [Pokemon, nil] the Pokémon fused into this one (nil if there is none) attr_accessor :fused # @return [Integer] this Pokémon's personal ID attr_accessor :personalID # Max total IVs IV_STAT_LIMIT = 31 # Max total EVs EV_LIMIT = 510 # Max EVs that a single stat can have EV_STAT_LIMIT = 252 # Maximum length a Pokémon's nickname can be MAX_NAME_SIZE = 10 # Maximum number of moves a Pokémon can know at once MAX_MOVES = 4 def species_data return GameData::Species.get_species_form(@species, form_simple) end #============================================================================= # Species and form #============================================================================= # Changes the Pokémon's species and re-calculates its statistics. # @param species_id [Integer] id of the species to change this Pokémon to def species=(species_id) new_species_data = GameData::Species.get(species_id) return if @species == new_species_data.species @species = new_species_data.species @form = new_species_data.form if new_species_data.form != 0 @forced_form = nil @level = nil # In case growth rate is different for the new species @ability = nil calcStats end # @param check_species [Integer, Symbol, String] id of the species to check for # @return [Boolean] whether this Pokémon is of the specified species def isSpecies?(check_species) return @species == check_species || (GameData::Species.exists?(check_species) && @species == GameData::Species.get(check_species).species) end def form return @forced_form if !@forced_form.nil? return @form if $game_temp.in_battle calc_form = MultipleForms.call("getForm", self) self.form = calc_form if calc_form != nil && calc_form != @form return @form end def form_simple return @forced_form || @form end def form=(value) oldForm = @form @form = value @ability = nil yield if block_given? MultipleForms.call("onSetForm", self, value, oldForm) calcStats pbSeenForm(self) end def setForm(value) self.form = value end def form_simple=(value) @form = value calcStats end #============================================================================= # Level #============================================================================= # @return [Integer] this Pokémon's level def level @level = PBExperience.pbGetLevelFromExperience(@exp, growth_rate) if !@level return @level end # Sets this Pokémon's level. The given level must be between 1 and the # maximum level (defined in {PBExperience}). # @param value [Integer] new level (between 1 and the maximum level) def level=(value) if value < 1 || value > PBExperience.maxLevel raise ArgumentError.new(_INTL("The level number ({1}) is invalid.", value)) end @exp = PBExperience.pbGetStartExperience(value, growth_rate) @level = value end # Sets this Pokémon's Exp. Points. # @param value [Integer] new experience points def exp=(value) @exp = value @level = nil end # @return [Boolean] whether this Pokémon is an egg def egg? return @steps_to_hatch > 0 end alias isEgg? egg? # @return [Integer] this Pokémon's growth rate (from PBGrowthRates) def growth_rate return species_data.growth_rate end # @return [Integer] this Pokémon's base Experience value def base_exp return species_data.base_exp end # @return [Float] a number between 0 and 1 indicating how much of the current level's # Exp this Pokémon has def exp_fraction lvl = self.level return 0.0 if lvl >= PBExperience.maxLevel g_rate = growth_rate start_exp = PBExperience.pbGetStartExperience(lvl, g_rate) end_exp = PBExperience.pbGetStartExperience(lvl + 1, g_rate) return (@exp - start_exp).to_f / (end_exp - start_exp) end #============================================================================= # Status #============================================================================= # Sets the Pokémon's health. # @param value [Integer] new HP value def hp=(value) @hp = value.clamp(0, @totalhp) heal_status if @hp == 0 end # Sets this Pokémon's status. See {PBStatuses} for all possible status effects. # @param value [Integer, Symbol, String] status to set (from {PBStatuses}) def status=(value) new_status = getID(PBStatuses, value) if !new_status raise ArgumentError, _INTL('Attempted to set {1} as Pokémon status', value.class.name) end @status = new_status end # @return [Boolean] whether the Pokémon is not fainted and not an egg def able? return !egg? && @hp > 0 end alias isAble? able? # @return [Boolean] whether the Pokémon is fainted def fainted? return !egg? && @hp <= 0 end alias isFainted? fainted? # Heals all HP of this Pokémon. def heal_HP return if egg? @hp = @totalhp end # Heals the status problem of this Pokémon. def heal_status return if egg? @status = PBStatuses::NONE @statusCount = 0 end # Restores all PP of this Pokémon. If a move index is given, restores the PP # of the move in that index. # @param move_index [Integer] index of the move to heal (-1 if all moves # should be healed) def heal_PP(move_index = -1) return if egg? if move_index >= 0 @moves[move_index].pp = @moves[move_index].total_pp else @moves.each { |m| m.pp = m.total_pp } end end # Heals all HP, PP, and status problems of this Pokémon. def heal return if egg? heal_HP heal_status heal_PP end #============================================================================= # Types #============================================================================= # @return [Integer] this Pokémon's first type def type1 return species_data.type1 end # @return [Integer] this Pokémon's second type, or the first type if none is defined def type2 sp_data = species_data return sp_data.type2 || sp_data.type1 end # @return [Array] an array of this Pokémon's types def types sp_data = species_data ret = [sp_data.type1] ret.push(sp_data.type2) if sp_data.type2 && sp_data.type2 != sp_data.type1 return ret end # @param type [Integer, Symbol, String] type to check # @return [Boolean] whether this Pokémon has the specified type def hasType?(type) type = GameData::Type.get(type).id return self.types.include?(type) end #============================================================================= # Gender #============================================================================= # @return [0, 1, 2] this Pokémon's gender (0 = male, 1 = female, 2 = genderless) def gender if !@gender gender_rate = species_data.gender_rate case gender_rate when PBGenderRates::AlwaysMale then @gender = 0 when PBGenderRates::AlwaysFemale then @gender = 1 when PBGenderRates::Genderless then @gender = 2 else @gender = ((@personalID & 0xFF) < PBGenderRates.genderByte(gender_rate)) ? 1 : 0 end end return @gender end # Sets this Pokémon's gender to a particular gender (if possible). # @param value [0, 1] new gender (0 = male, 1 = female) def gender=(value) return if singleGendered? @gender = value if value.nil? || value == 0 || value == 1 end # Makes this Pokémon male. def makeMale; self.gender = 0; end # Makes this Pokémon female. def makeFemale; self.gender = 1; end # @return [Boolean] whether this Pokémon is male def male?; return self.gender == 0; end alias isMale? male? # @return [Boolean] whether this Pokémon is female def female?; return self.gender == 1; end alias isFemale? female? # @return [Boolean] whether this Pokémon is genderless def genderless?; return self.gender == 2; end alias isGenderless? genderless? # @return [Boolean] whether this Pokémon species is restricted to only ever being one # gender (or genderless) def singleGendered? gender_rate = species_data.gender_rate return [PBGenderRates::AlwaysMale, PBGenderRates::AlwaysFemale, PBGenderRates::Genderless].include?(gender_rate) end alias isSingleGendered? singleGendered? #============================================================================= # Shininess #============================================================================= # @return [Boolean] whether this Pokémon is shiny (differently colored) def shiny? if @shiny.nil? a = @personalID ^ @owner.id b = a & 0xFFFF c = (a >> 16) & 0xFFFF d = b ^ c @shiny = d < SHINY_POKEMON_CHANCE end return @shiny end alias isShiny? shiny? #============================================================================= # Ability #============================================================================= # @return [Integer] the index of this Pokémon's ability def ability_index @ability_index = (@personalID & 1) if !@ability_index return @ability_index end # @return [GameData::Ability, nil] an Ability object corresponding to this Pokémon's ability def ability return GameData::Ability.try_get(ability_id) end # @return [Symbol, nil] the ability symbol of this Pokémon's ability def ability_id if !@ability sp_data = species_data abil_index = ability_index if abil_index >= 2 # Hidden ability @ability = sp_data.hidden_abilities[abil_index - 2] abil_index = (@personalID & 1) if !@ability end if !@ability # Natural ability or no hidden ability defined @ability = sp_data.abilities[abil_index] || sp_data.abilities[0] end end return @ability end def ability=(value) return if value && !GameData::Ability.exists?(value) @ability = (value) ? GameData::Ability.get(value).id : value end # Returns whether this Pokémon has a particular ability. If no value # is given, returns whether this Pokémon has an ability set. # @param check_ability [Symbol, GameData::Ability, Integer] ability ID to check # @return [Boolean] whether this Pokémon has a particular ability or # an ability at all def hasAbility?(check_ability = nil) current_ability = self.ability return !current_ability.nil? if check_ability.nil? return current_ability == check_ability end # @return [Boolean] whether this Pokémon has a hidden ability def hasHiddenAbility? return ability_index >= 2 end # @return [Array>] the abilities this Pokémon can have, # where every element is [ability ID, ability index] def getAbilityList ret = [] sp_data = species_data sp_data.abilities.each_with_index { |a, i| ret.push([a, i]) if a } sp_data.hidden_abilities.each_with_index { |a, i| ret.push([a, i + 2]) if a } return ret end #============================================================================= # Nature #============================================================================= # @return [GameData::Nature, nil] a Nature object corresponding to this Pokémon's nature def nature @nature = GameData::Nature.get(@personalID % 25).id if !@nature return GameData::Nature.try_get(@nature) end def nature_id return @nature end # Sets this Pokémon's nature to a particular nature. # @param value [Integer, String, Symbol] nature to change to def nature=(value) return if value && !GameData::Nature.exists?(value) @nature = (value) ? GameData::Nature.get(value).id : value calcStats if !@nature_for_stats end # Returns the calculated nature, taking into account things that change its # stat-altering effect (i.e. Gen 8 mints). Only used for calculating stats. # @return [GameData::Nature, nil] this Pokémon's calculated nature def nature_for_stats return GameData::Nature.try_get(@nature_for_stats) if @nature_for_stats return self.nature end def nature_for_stats_id return @nature_for_stats end # If defined, this Pokémon's nature is considered to be this when calculating stats. # @param value [Integer, nil] ID of the nature to use for calculating stats def nature_for_stats=(value) return if value && !GameData::Nature.exists?(value) @nature_for_stats = (value) ? GameData::Nature.get(value).id : value calcStats end # Returns whether this Pokémon has a particular nature. If no value is given, # returns whether this Pokémon has a nature set. # @param nature [Integer] nature ID to check # @return [Boolean] whether this Pokémon has a particular nature or a nature # at all def hasNature?(check_nature = nil) return !@nature_id.nil? if check_nature.nil? return self.nature == check_nature end #============================================================================= # Items #============================================================================= # @return [GameData::Item, nil] an Item object corresponding to this Pokémon's item def item return GameData::Item.try_get(@item) end def item_id return @item end # Gives an item to this Pokémon to hold. # @param value [Symbol, GameData::Item, Integer, nil] ID of the item to give # to this Pokémon def item=(value) return if value && !GameData::Item.exists?(value) @item = (value) ? GameData::Item.get(value).id : value end # Returns whether this Pokémon is holding an item. If an item id is passed, # returns whether the Pokémon is holding that item. # @param check_item [Symbol, GameData::Item, Integer] item ID to check # @return [Boolean] whether the Pokémon is holding the specified item or # an item at all def hasItem?(check_item = nil) return !@item.nil? if check_item.nil? return self.item == check_item end # @return [Array] the items this species can be found holding in the wild def wildHoldItems sp_data = species_data return [sp_data.wild_item_common, sp_data.wild_item_uncommon, sp_data.wild_item_rare] end # @return [Mail, nil] mail held by this Pokémon (nil if there is none) def mail @mail = nil if @mail && (!@mail.item || !hasItem?(@mail.item)) return @mail end # If mail is a Mail object, gives that mail to this Pokémon. If nil is given, # removes the held mail. # @param mail [Mail, nil] mail to be held by this Pokémon def mail=(mail) if !mail.nil? && !mail.is_a?(Mail) raise ArgumentError, _INTL('Invalid value {1} given', mail.inspect) end @mail = mail end #============================================================================= # Moves #============================================================================= # @return [Integer] the number of moves known by the Pokémon def numMoves return @moves.length end # @param move_id [Integer, Symbol, String] ID of the move to check # @return [Boolean] whether the Pokémon knows the given move def hasMove?(move_id) move_data = GameData::Move.try_get(move_id) return false if !move_data return @moves.any? { |m| m.id == move_data.id } end alias knowsMove? hasMove? # Returns the list of moves this Pokémon can learn by levelling up. # @return [Array>] this Pokémon's move list, where every element is [level, move ID] def getMoveList return species_data.moves end # Sets this Pokémon's movelist to the default movelist it originally had. def resetMoves this_level = self.level # Find all level-up moves that self could have learned moveset = self.getMoveList knowable_moves = [] moveset.each { |m| knowable_moves.push(m[1]) if m[0] <= this_level } # Remove duplicates (retaining the latest copy of each move) knowable_moves = knowable_moves.reverse knowable_moves |= [] knowable_moves = knowable_moves.reverse # Add all moves @moves.clear first_move_index = knowable_moves.length - MAX_MOVES first_move_index = 0 if first_move_index < 0 for i in first_move_index...knowable_moves.length @moves.push(Pokemon::Move.new(knowable_moves[i])) end end # Silently learns the given move. Will erase the first known move if it has to. # @param move_id [Integer, Symbol, String] ID of the move to learn def learn_move(move_id) move_data = GameData::Move.try_get(move_id) return if !move_data # Check if self already knows the move; if so, move it to the end of the array @moves.each_with_index do |m, i| next if m.id != move_data.id @moves.push(m) @moves.delete_at(i) return end # Move is not already known; learn it @moves.push(Pokemon::Move.new(move_data.id)) # Delete the first known move if self now knows more moves than it should @moves.shift if numMoves > MAX_MOVES end # Deletes the given move from the Pokémon. # @param move_id [Integer, Symbol, String] ID of the move to delete def forget_move(move_id) move_data = GameData::Move.try_get(move_id) return if !move_data @moves.delete_if { |m| m.id == move_data.id } end # Deletes the move at the given index from the Pokémon. # @param index [Integer] index of the move to be deleted def forget_move_at_index(index) @moves.delete_at(index) end # Deletes all moves from the Pokémon. def forget_all_moves @moves.clear end # Copies currently known moves into a separate array, for Move Relearner. def record_first_moves clear_first_moves @moves.each { |m| @first_moves.push(m.id) } end # Adds a move to this Pokémon's first moves. # @param move_id [Integer, Symbol, String] ID of the move to add def add_first_move(move_id) move_data = GameData::Move.try_get(move_id) @first_moves.push(move_data.id) if move_data && !@first_moves.include?(move_data.id) end # Removes a move from this Pokémon's first moves. # @param move_id [Integer, Symbol, String] ID of the move to remove def remove_first_move(move_id) move_data = GameData::Move.try_get(move_id) @first_moves.delete(move_data.id) if move_data end # Clears this Pokémon's first moves. def clear_first_moves @first_moves.clear end # @param move_id [Integer, Symbol, String] ID of the move to check # @return [Boolean] whether the Pokémon is compatible with the given move def compatible_with_move?(move_id) move_data = GameData::Move.try_get(move_id) return move_data && species_data.tutor_moves.include?(move_data.id) end #============================================================================= # Ribbons #============================================================================= # @return [Integer] the number of ribbons this Pokémon has def numRibbons return @ribbons.length end # @param ribbon [Integer, Symbol, String] ribbon ID to check # @return [Boolean] whether this Pokémon has the specified ribbon def hasRibbon?(ribbon) ribbon = getID(PBRibbons, ribbon) return ribbon > 0 && @ribbons.include?(ribbon) end # Gives a ribbon to this Pokémon. # @param ribbon [Integer, Symbol, String] ID of the ribbon to give def giveRibbon(ribbon) ribbon = getID(PBRibbons, ribbon) return if ribbon == 0 @ribbons.push(ribbon) if !@ribbons.include?(ribbon) end # Replaces one ribbon with the next one along, if possible. def upgradeRibbon(*arg) for i in 0...arg.length - 1 for j in 0...@ribbons.length next if @ribbons[j] != getID(PBRibbons, arg[i]) @ribbons[j] = getID(PBRibbons, arg[i + 1]) return @ribbons[j] end end if !hasRibbon?(arg[arg.length - 1]) first_ribbon = getID(PBRibbons, arg[0]) giveRibbon(first_ribbon) return first_ribbon end return 0 end # Removes the specified ribbon from this Pokémon. # @param ribbon [Integer, Symbol, String] id of the ribbon to remove def takeRibbon(ribbon) return if !@ribbons ribbon = getID(PBRibbons, ribbon) return if ribbon == 0 for i in 0...@ribbons.length next if @ribbons[i] != ribbon @ribbons[i] = nil break end @ribbons.compact! end # Removes all ribbons from this Pokémon. def clearAllRibbons @ribbons.clear end #============================================================================= # Pokérus #============================================================================= # @return [Integer] the Pokérus infection stage for this Pokémon def pokerusStrain return @pokerus / 16 end # Returns the Pokérus infection stage for this Pokémon. The possible stages are # 0 (not infected), 1 (infected) and 2 (cured) # @return [0, 1, 2] current Pokérus infection stage def pokerusStage return 0 if @pokerus == 0 return ((@pokerus % 16) == 0) ? 2 : 1 end # Gives this Pokémon Pokérus (either the specified strain or a random one). # @param strain [Integer] Pokérus strain to give def givePokerus(strain = 0) return if self.pokerusStage == 2 # Can't re-infect a cured Pokémon strain = rand(1, 16) if strain <= 0 || strain >= 16 time = 1 + (strain % 4) @pokerus = time @pokerus |= strain << 4 end # Resets the infection time for this Pokémon's Pokérus (even if cured). def resetPokerusTime return if @pokerus == 0 strain = @pokerus % 16 time = 1 + (strain % 4) @pokerus = time @pokerus |= strain << 4 end # Reduces the time remaining for this Pokémon's Pokérus (if infected). def lowerPokerusCount return if self.pokerusStage != 1 @pokerus -= 1 end #============================================================================= # Ownership, obtained information #============================================================================= # Changes this Pokémon's owner. # @param new_owner [Owner] the owner to change to def owner=(new_owner) validate new_owner => Owner @owner = new_owner end # @param trainer [PlayerTrainer, NPCTrainer] the trainer to compare to the original trainer # @return [Boolean] whether the given trainer is not this Pokémon's original trainer def foreign?(trainer) return @owner.id != trainer.id || @owner.name != trainer.name end alias isForeign? foreign? # @return [Time] the time when this Pokémon was obtained def timeReceived return Time.at(@timeReceived) end # Sets the time when this Pokémon was obtained. # @param value [Integer, Time, #to_i] time in seconds since Unix epoch def timeReceived=(value) @timeReceived = value.to_i end # @return [Time] the time when this Pokémon hatched def timeEggHatched return (obtain_method == 1) ? Time.at(@timeEggHatched) : nil end # Sets the time when this Pokémon hatched. # @param value [Integer, Time, #to_i] time in seconds since Unix epoch def timeEggHatched=(value) @timeEggHatched = value.to_i end #============================================================================= # Other #============================================================================= # @return [String] the name of this Pokémon def name return (nicknamed?) ? @name : speciesName end # @param value [String] the nickname of this Pokémon def name=(value) value = nil if !value || value.empty? || value == speciesName @name = value end # @return [Boolean] whether this Pokémon has been nicknamed def nicknamed? return @name && !@name.empty? end # @return [String] the species name of this Pokémon def speciesName return species_data.name end # @return [String] a string stating the Unown form of this Pokémon def unownShape return "ABCDEFGHIJKLMNOPQRSTUVWXYZ?!"[@form, 1] end # @return [Integer] the height of this Pokémon in decimetres (0.1 metres) def height return species_data.height end # @return [Integer] the weight of this Pokémon in hectograms (0.1 kilograms) def weight return species_data.weight end # @return [Array] the EV yield of this Pokémon (an array of six values) def evYield return species_data.evs.clone end # Changes the happiness of this Pokémon depending on what happened to change it. # @param method [String] the happiness changing method (e.g. 'walking') def changeHappiness(method) gain = 0 happiness_range = @happiness / 100 case method when "walking" gain = [2, 2, 1][happiness_range] when "levelup" gain = [5, 4, 3][happiness_range] when "groom" gain = [10, 10, 4][happiness_range] when "evberry" gain = [10, 5, 2][happiness_range] when "vitamin" gain = [5, 3, 2][happiness_range] when "wing" gain = [3, 2, 1][happiness_range] when "machine", "battleitem" gain = [1, 1, 0][happiness_range] when "faint" gain = -1 when "faintbad" # Fainted against an opponent that is 30+ levels higher gain = [-5, -5, -10][happiness_range] when "powder" gain = [-5, -5, -10][happiness_range] when "energyroot" gain = [-10, -10, -15][happiness_range] when "revivalherb" gain = [-15, -15, -20][happiness_range] else raise _INTL("Unknown happiness-changing method: {1}", method.to_s) end if gain > 0 gain += 1 if @obtain_map == $game_map.map_id gain += 1 if @poke_ball == :LUXURYBALL gain = (gain * 1.5).floor if hasItem?(:SOOTHEBELL) end @happiness = (@happiness + gain).clamp(0, 255) end #============================================================================= # Stat calculations #============================================================================= # @return [Array] this Pokémon's base stats, an array of six values def baseStats return species_data.base_stats.clone end # Returns this Pokémon's effective IVs, taking into account Hyper Training. # Only used for calculating stats. # @return [Array] array containing this Pokémon's effective IVs def calcIV ret = self.iv.clone PBStats.eachStat { |s| ret[s] = IV_STAT_LIMIT if @ivMaxed[s] } return ret end # @return [Integer] the maximum HP of this Pokémon def calcHP(base, level, iv, ev) return 1 if base == 1 # For Shedinja return ((base * 2 + iv + (ev / 4)) * level / 100).floor + level + 10 end # @return [Integer] the specified stat of this Pokémon (not used for total HP) def calcStat(base, level, iv, ev, nat) return ((((base * 2 + iv + (ev / 4)) * level / 100).floor + 5) * nat / 100).floor end # Recalculates this Pokémon's stats. def calcStats base_stats = self.baseStats this_level = self.level this_IV = self.calcIV # Format stat multipliers due to nature nature_mod = [] PBStats.eachStat { |s| nature_mod[s] = 100 } this_nature = self.nature_for_stats if this_nature this_nature.stat_changes.each { |change| nature_mod[change[0]] += change[1] } end # Calculate stats stats = [] PBStats.eachStat do |s| if s == PBStats::HP stats[s] = calcHP(base_stats[s], this_level, this_IV[s], @ev[s]) else stats[s] = calcStat(base_stats[s], this_level, this_IV[s], @ev[s], nature_mod[s]) end end hpDiff = @totalhp - @hp @totalhp = stats[PBStats::HP] @hp = @totalhp - hpDiff @attack = stats[PBStats::ATTACK] @defense = stats[PBStats::DEFENSE] @spatk = stats[PBStats::SPATK] @spdef = stats[PBStats::SPDEF] @speed = stats[PBStats::SPEED] end #============================================================================= # Pokémon creation #============================================================================= # Creates a copy of this Pokémon and returns it. # @return [Pokemon] a copy of this Pokémon def clone ret = super ret.iv = @iv.clone ret.ivMaxed = @ivMaxed.clone ret.ev = @ev.clone ret.moves = [] @moves.each_with_index { |m, i| ret.moves[i] = m.clone } ret.first_moves = @first_moves.clone ret.owner = @owner.clone ret.ribbons = @ribbons.clone return ret end # Creates a new Pokémon object. # @param species [Symbol, String, Integer] Pokémon species # @param level [Integer] Pokémon level # @param owner [Owner, PlayerTrainer, NPCTrainer] Pokémon owner (the player by default) # @param withMoves [Boolean] whether the Pokémon should have moves def initialize(species, level, owner = $Trainer, withMoves = true) species_data = GameData::Species.get(species) @species = species_data.species @form = species_data.form @forced_form = nil @time_form_set = nil self.level = level @steps_to_hatch = 0 heal_status @gender = nil @shiny = nil @ability_index = nil @ability = nil @nature = nil @nature_for_stats = nil @item = nil @mail = nil @moves = [] resetMoves if withMoves @first_moves = [] @ribbons = [] @cool = 0 @beauty = 0 @cute = 0 @smart = 0 @tough = 0 @sheen = 0 @pokerus = 0 @name = nil @happiness = species_data.happiness @poke_ball = :POKEBALL @markings = 0 @iv = [] @ivMaxed = [] @ev = [] PBStats.eachStat do |s| @iv[s] = rand(IV_STAT_LIMIT + 1) @ev[s] = 0 end if owner.is_a?(Owner) @owner = owner elsif owner.is_a?(PlayerTrainer) || owner.is_a?(NPCTrainer) @owner = Owner.new_from_trainer(owner) else @owner = Owner.new(0, '', 2, 2) end @obtain_method = 0 # Met @obtain_method = 4 if $game_switches && $game_switches[FATEFUL_ENCOUNTER_SWITCH] @obtain_map = ($game_map) ? $game_map.map_id : 0 @obtain_text = nil @obtain_level = level @hatched_map = 0 @timeReceived = pbGetTimeNow.to_i @timeEggHatched = nil @fused = nil @personalID = rand(2 ** 16) | rand(2 ** 16) << 16 @hp = 1 @totalhp = 1 calcStats if @form == 0 f = MultipleForms.call("getFormOnCreation", self) if f self.form = f resetMoves if withMoves end end end end