• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Solving the IV Problem FOR GOOD with a simple code tweak that works in any game and skips over RNG grinding!

429
Posts
4
Years
Step 1: Open your game, and open Script Editor.

Step 2: While holding CTRL and Shift, press F.

Step 3: Copypaste in "Returns this Pokémon's effective IVs, taking into account Hyper Training" without the quotation marks, and hit Start Search.

Step 4: Double-Click the one line of code displayed in the search results, and change it so that it looks like this:

Code:
  # Returns this Pokémon's effective IVs, taking into account Hyper Training.
  # Only used for calculating stats.
  # @return [Hash<Integer>] hash containing this Pokémon's effective IVs
  def calcIV
    this_ivs = self.iv
    ret = {}
    GameData::Stat.each_main do |s|
      ret[s.id] = 31#or whatever the maximum IVs are in your game, I personally set it to 32
#      ret[s.id] = (@ivMaxed[s.id]) ? IV_STAT_LIMIT : this_ivs[s.id]
    end
#end
    return ret
  end

MISSION COMPLETE!!! Now your Pokemon game, when calculating the stats of each Pokemon, will treat the Pokemon as if it has Perfect IVs. Resetting endlessly, grinding for and using expensive items, and using the Ditto method for better IVs, it's all a thing of the past! The Player's Pokemon will ALWAYS be the best they can be, and the same is true for all Pokemon the player faces!

No matter what your Pokemon's IVs are, stat calculation will pretend they are perfect, even if they have a specific IV combination for Hidden Power, it doesn't matter, stat calculation will pretend they are the highest possible. After all, there is literally never a reason not to have the best possible IVs. Unless you want to minimize Play Rough damage taken by a spectacularly minuscule amount so much, you're fine with trading away a workable Attack stat. But anything with an Attack stat low enough to not mind giving it up won't take much Play Rough damage anyway.

Now your players can spend more time playing the game, and less time trying to grind RNG. This makes life better for casual players who don't know what IVs are and don't want to care, and it speeds life up for hardcore players who want a game full of perfect-IV Pokemon, without stepping on anybody's toes! After all, there will always be shiny Pokemon for them to RNG grind for if they are so inclined.

Now that this method has been discovered, I would love to see it become the new standard in all future games, but it's up to you whether you want to include it in your game or not. You DO NOT have to give credit. Though it would be nice if you did. In fact, feel free to post this on other Pokemon fangame websites! I want this to spread. I want this to become the new normal.

It would be great if Pokemon Essentials' developers put this into the next Essentials version as another one of those TRUE/FALSE options. But that doesn't have to be done. Would be easy, though.

Update: It works BRILLIANTLY. Video to prove it: https://www.youtube.com/watch?v=X4c6m6NxF24
 
Last edited:
429
Posts
4
Years
I decided to fix EVs, too.

First CTRL+F "def evYield" and change it to this
Code:
  def evYield
    return 0
  end

Then you copypaste the following code until "def calcIV", "def calcHP", and "def calcStat" look like this.
Code:
  def calcIV
    this_ivs = self.iv
    ret = {}
    GameData::Stat.each_main do |s|
      ret[s.id] = 32
    end
    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 + 64) * 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 + 64) * level / 100).floor + 5) * nat / 100).floor
  end

Now instead of looking at the EVs of any Pokemon when calculating its stats, it will always treat each EV as 256, and the resulting stat boost as 64. This is neater than the 255/252 and 63 boost used by official Pokemon games. Results in superior higher numbers, too.

The same is true for IVs, which now always read as the new maximum of 32. You might want to go and set the maximum number of IVs a Pokemon can have to 32 and the maximum number of EVs to 1536, which is 256 times 6.

The individual IVs and EVs of each Pokemon can be anything. The game's stat calculation will treat them as if they are maxed. But for separate checks like the Bug Catching contest, the Hidden Power Type Checks, that guy who wants a big Barboarch or whatever, the Effort Ribbon NPC, and so on, the game will check the actual stats.

And just like that, the biggest barrier keeping new competitive Pokemon players out of understanding the game has been removed. It's not like EVs and IVs really add anything to the meta outside of those Pokemon that could be Attackers or Special Attackers depending on EV spread. Now they will have the EVs for both, and whether they're used as one or the other depends on Movepool.

Combine this with a Pokeball that sets caught Pokemon to lv100, and another that sets it to lv75, and after you add a Move Relearner option to the Pokemon Menu used for switching pokemon and their moves around, you might be able to take a Pokemon from freshly caught to competitive battle-ready in under a minute!

Speaking of which, here is the code my Ball changes. It includes changes to make these balls always work, and ensure Cherish Balls turn your pokemon Shiny while Safari balls become reuseable and so on. I commented out the "Dusk Ball=Shadow Pokemon" effect in case you don't want Shadow Pokemon in your game.

Code:
#===============================================================================
# IsUnconditional
#===============================================================================
BallHandlers::IsUnconditional.add(:MASTERBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:GREATBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:POKEBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:SAFARIBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:CHERISHBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:DREAMBALL,proc { |ball,battle,battler|
  next true
})
BallHandlers::IsUnconditional.add(:ULTRABALL,proc { |ball,battle,battler|
  next true
})

Code:
#===============================================================================
# OnCatch
#===============================================================================
BallHandlers::OnCatch.add(:HEALBALL,proc { |ball,battle,pkmn|
  pkmn.heal
})
BallHandlers::OnCatch.add(:DREAMBALL,proc { |ball,battle,pkmn|
  pkmn.heal
  pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.ability_index = 3
  pkmn.calc_stats
})
BallHandlers::OnCatch.add(:CHERISHBALL,proc { |ball,battle,pkmn|
  pkmn.heal
  pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.shiny = true
  pkmn.calc_stats
})
#BallHandlers::OnCatch.add(:DUSKBALL,proc { |ball,battle,pkmn|
# pkmn.heal
# pkmn.iv[:HP] = true
# pkmn.iv[:ATTACK] = true
# pkmn.iv[:DEFENSE] = true
# pkmn.iv[:SPECIAL_ATTACK] = true
# pkmn.iv[:SPECIAL_DEFENSE] = true
# pkmn.iv[:SPEED] = true
# pkmn.makeShadow
# pkmn.calc_stats
# pkmn.heal
# pkmn.calc_stats
#})
BallHandlers::OnCatch.add(:GREATBALL,proc { |ball,battle,pkmn|
  pkmn.heal
    pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.level = 50
  pkmn.calc_stats
    pkmn.heal
    pkmn.calc_stats
})
BallHandlers::OnCatch.add(:ULTRABALL,proc { |ball,battle,pkmn|
  pkmn.heal
    pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.level = 75
  pkmn.calc_stats
    pkmn.heal
})
BallHandlers::OnCatch.add(:MASTERBALL,proc { |ball,battle,pkmn|
  pkmn.heal
    pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.level = 100
  pkmn.calc_stats
    pkmn.heal
})
BallHandlers::OnCatch.add(:PREMIERBALL,proc { |ball,battle,pkmn|
  pkmn.heal
    pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
pkmn.beauty = 255
pkmn.cool = 255
pkmn.cute = 255
pkmn.smart = 255
pkmn.tough = 255
pkmn.sheen = 255
  pkmn.calc_stats
    pkmn.heal
})
BallHandlers::OnCatch.add(:POKEBALL,proc { |ball,battle,pkmn|
  pkmn.heal
      pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.level = 30
  pkmn.calc_stats
    pkmn.heal
})
BallHandlers::OnCatch.add(:SAFARIBALL,proc { |ball,battle,pkmn|
  pkmn.heal
      pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  	pkmn.item = :SAFARIBALL
      pkmn.calc_stats
    pkmn.heal
})
BallHandlers::OnCatch.add(:FRIENDBALL,proc { |ball,battle,pkmn|
  pkmn.happiness = 255
})
 
429
Posts
4
Years
This makes me wonder what other Quality Of Life features could be on the table...

Perhaps if every move was replaced with one "Attack" in Learned Move sets?

Code could change the name of this "Attack" to suit Type1.
 
Last edited:
429
Posts
4
Years
Update: To make this work properly in the new Pokemon Essentials V20, this change must be made:

CTRL+F "pbGainEVsOne" and turn it into this:
Code:
  def pbGainEVsOne(idxParty, defeatedBattler)
  end

This fixes the crashing issue I was having when trying to redo my tweaks in V20.

Edit: Also, they changed the wording for Pokeball effects.

Code:
Battle::PokeBallEffects::OnCatch.add(:CHERISHBALL, proc { |ball, battle, pkmn|
  pkmn.heal
  pkmn.iv[:HP] = true
  pkmn.iv[:ATTACK] = true
  pkmn.iv[:DEFENSE] = true
  pkmn.iv[:SPECIAL_ATTACK] = true
  pkmn.iv[:SPECIAL_DEFENSE] = true
  pkmn.iv[:SPEED] = true
  pkmn.shiny = true
  pkmn.calc_stats
})

This should work now.

edit: Take this, too. These coding secrets can help anyone's game. Feels nice to be able to read text in a Pokemon Essentials game without needing to speed it up using Cheat Engine.

Code:
  def self.pbSettingToTextSpeed(speed)
    case speed
#    when 0 then return 2
#    when 1 then return 1
#    when 2 then return -2
          when 0 then return 1
    when 1 then return -8
    when 2 then return -16
    when 3 then return -64#69 hahaha
    end
    return TEXT_SPEED || 1
  end
 
Last edited:
429
Posts
4
Years
Time for an exciting new update in the world of QOL features! Now with V20.1 support!

Would you like the levels of your Pokemon to matter less during stat calculation, making level grinding less necessary? Just CTRL+F "defense = [(defense * multipliers[:defense_multiplier]).round, 1].max" and replace the line that starts with "Damage =" with this!

Code:
damage  = ((((2.0 * (30 + (user.level / 2.5)) / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2

Don't forget the similar code in "AI_Move_Utilities"!

Code:
damage  = ((((2.0 * (30 + (user.level / 2.5)) / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2

Finally, replace the Pokemon Stat Calculation code for HP and Base Stats in "Pokemon" with this.

Code:
  def calcHP(base, level, iv, ev)
    return 1 if base == 1   # For Shedinja
    return (((base * 2) + 32 + 64) * (30 + (level / 2.5)) / 50).floor + (30 + (level / 2.5)) + 10
  end

  def calcStat(base, level, iv, ev, nat)
    return (((((base * 2) + 32 + 64) * (30 + (level / 2.5)) / 50).floor + 5) * nat / 100).floor
  end

Now, the gap between level 1 and lv50 is much smaller. A lv1 Pokemon in your game will basically be around lv30 stat-wise, slowly growing towards where he would normally be at lv50. Why replace the actual level with "30 plus (level divided by 2.5)"? 50 divided by 2.5 is 20, and 30+20=50. At level 50, you're adding 20 de facto levels to your base level of 30, resulting in the power of a normal level 50 Pokemon when you finally get to level 50.

Why did I design it this way? Well, I liked "Fixed Levels Mode", and I loved the way it allows low-level Pokemon to make a good first impression on you and matter when you return to a low-level area, but I could tell this stat equalization would get in the way of those scenes where you effortlessly steamroll your way through many enemy trainers in a row because their Pokemon are inferior to yours, and those scenes where you fight an unwinnable boss battle early on during the story so you'll want revenge when you fight this boss later on in the story with a team that can actually win. Those scenes would still be possible if the weak enemy trainers had fewer Pokemon than you per team and the unwinnable boss fight got to you very early on(Perhaps with a legendary?), before you have a chance to have anything threatening in your team, or anything at all besides your starter and maybe some early game fodder. I want the level curve of my game reduced in severity for a smoother experience, not removed outright. Also, when you make selecting the moves you want on your Pokemon regardless of level easy, access to powerful moves isn't something you can use to balance the power level of the moves of your Pokemon.

I designed this code for a game where the level cap is 50, but this version will work with games where the level cap is 100.

Remember, put this in both "AI_Move_Utilities" and "Move_UsageCalculations". You don't want your opponent's Pokemon using a version of this code that's different from yours.
Code:
damage  = ((((2.0 * (30 + ((user.level / 2) / 2.5)) / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2

Code:
  def calcHP(base, level, iv, ev)
    return 1 if base == 1   # For Shedinja
    return (((base * 2) + 32 + 64) * (30 + ((level / 2) / 2.5)) / 50).floor + (30 + (level / 2.5)) + 10
  end

  def calcStat(base, level, iv, ev, nat)
    return (((((base * 2) + 32 + 64) * (30 + ((level / 2) / 2.5)) / 50).floor + 5) * nat / 100).floor
  end

Now you can enjoy the slow growth from lv30 to lv50 power-wise as you grow from lv1 to lv100!

Want to completely and literally remove levels from the equation? Here's code for a version with fixed levels, calculating all Pokemon as if they were level 50 no matter what their level actually is.
Code:
damage  = ((((2.0 * level / 5) + 2).floor * baseDmg * atk / defense).floor / 50).floor + 2

Code:
  def calcHP(base, level, iv, ev)
    return 1 if base == 1   # For Shedinja
    return (((base * 2) + 32 + 64) * level / 50).floor + (30 + (level / 2.5)) + 10
  end

  def calcStat(base, level, iv, ev, nat)
    return (((((base * 2) + 32 + 64) * level / 50).floor + 5) * nat / 100).floor
  end

I hope you all enjoy using this code more than I enjoyed writing it.
 
Back
Top