• Hi, Guest!
    Some images might be missing as we move away from using embedded images, sorry for the mess!
    From now on, you'll be required to use a third party to host images. You can learn how to add images here, and if your thread is missing images you can request them here.
    Do not use Discord to host any images you post, these links expire quickly!
Scripted Exp Yield

v20.1 Scripted Exp Yield 2022-12-21

This resource pertains to version 20.1 of Pokémon Essentials.
Pokémon Essentials Version
v20.1 ➖
You may already be aware of the formula used to calculate a Pokémon's experience yield. (If you're not, Buttjuice has a post on it here) This formula takes out the guesswork, but there's still some busywork by punching in the formula over and over for new Pokémon - so I made a script to leave that all up to the game.

Please note that this script is probably not going to be a simple plug-and-play - you'll have to follow the instructions (and possibly make further changes) depending on what suits your needs.

Code​

Paste in a new script section above Main.
Ruby:
module GameData
  class Species
 
    FIRST_STAGE_MULT  = 4.0
    SECOND_STAGE_MULT = 7.0
    THIRD_STAGE_MULT  = 9.0
    SOLO_MULT         = 7.0
    LEGENDARY_MULT    = 9.0
    BONUS_MULT        = 2.5
 
    def evo_stage_array
      base = get_baby_species
      ret = [base]
      unless base==species
        base_data = GameData::Species.get(base)
        base_data.get_evolutions(true).each do |evo|   # [new_species, method, parameter, boolean]
          ret.push(evo[0]) if evo[0] == species || evo[0] == get_previous_species
        end
      end
      unless ret[1]==species || !ret[1]
        stage1_data = GameData::Species.get(ret[1])
        stage1_data.get_evolutions(true).each do |evo|   # [new_species, method, parameter, boolean]
          ret.push(evo[0]) if evo[0] == species || evo[0] == get_previous_species
        end
      end
      get_evolutions(true).each do |evo|   # [new_species, method, parameter, boolean]
        unless evo[3]
          ret.push(evo[0])
          break
        end
      end
      ret.push(species) if !ret.include?(species) #Prevents issues with Pokemon where method is None
      return ret
    end
 
    def calculated_exp
      array = evo_stage_array
      bst = base_stat_total.to_f
      stage = array.index(species)
      mult = [FIRST_STAGE_MULT,SECOND_STAGE_MULT,THIRD_STAGE_MULT][stage]
      mult = SOLO_MULT if array.length == 1
      mult = LEGENDARY_MULT if array.length == 1 && egg_groups.include?(:Undiscovered)
      mult *= BONUS_MULT if [:HAPPINY,:CHANSEY,:BLISSEY,:AUDINO].include?(species)
      ret = ((bst * mult)/20.0).round.to_i
      return ret
    end
 
  end
end

Mechanics​

The formula starts with the base stat total, then multiplies it by...
  • 4 if it's the first in an evolutionary line
  • 7 if it's the second in an evolutionary line, or if it's not part of an evolutionary line
  • 9 if it's the third in an an evolutionary line, or if it's a legendary
Then it's divided by 20, then rounded to the nearest number.

This is only designed to be used in a game where Pokémon can evolve twice at most. (Of course, if your game includes four-stage evolutionary lines, you'll already have to rework the formula to allow for a fourth-stage Pokémon. You're still welcome to use this code as a base if you'd like.)

A Pokémon is considered legendary if it has no evos or prevos and is in the Undiscovered Egg Group. You'll notice that this definition isn't quite 1:1 with Pokémon standards for legendary Pokémon. Urshifu evolves from Kubfu, though both are in the Undiscovered Egg Group. (Though Kubfu is actually treated as a normal first-stage mon for the sake of Exp yield) Unown has no evos/prevos and is in the Undiscovered Egg Group, but is not considered a legendary. I ultimately decided to do the simplest option that would be most accurate to canon rather than implement every exception to the rule at once.

To change this, look at this code block here -
Ruby:
      mult = [FIRST_STAGE_MULT,SECOND_STAGE_MULT,THIRD_STAGE_MULT][stage]
      mult = SOLO_MULT if array.length == 1
      mult = LEGENDARY_MULT if array.length == 1 && egg_groups.include?(:Undiscovered)
      mult *= BONUS_MULT if [:HAPPINY,:CHANSEY,:BLISSEY,:AUDINO].include?(species)
SOLO_MULT is the same as SECOND_STAGE_MULT, and LEGENDARY_MULT is the same as THIRD_STAGE_MULT. I just included both to make the reasoning a little more clear. (And also in the event anyone wants to toy around with exp yield through the base exp of Pokémon.) BONUS_MULT is multiplied with the existing mult to increase it - it's used for the Happiny family and Audino, to get their boosted yields. (It's off by about a point, though)

I tried to arrange it so that it would be pretty intuitive to try to add another condition. For example, Volcarona is treated as a legendary, so that means its multiplier should be set to the LEGENDARY mult -
Ruby:
      mult = LEGENDARY_MULT if species==:VOLCARONA
Or suppose I want to include Lucidious' Legendary Breeding - I might make a species flag "Legendary", and check for that instead of checking for the Undiscovered egg group.
Ruby:
      mult = LEGENDARY_MULT if has_flag?("Legendary")

Using the Script​

You've got a few options here, each with their own pros and cons.

Option 1 - Scripted Values, No Exceptions​

Simplest to implement, just add in this code -
Ruby:
class Pokemon
# @return [Integer] this Pokémon's base Experience value
  def base_exp
      return species_data.calculated_exp
  end
end
The game won't even look at the BaseExp value in the PBS, and will just use this formula when calculating exp. However, it won't reflect this in in the PBS or in any debug editors. (If your players are ever curious about the exp yield of a species - not common, but might be relevant if you plan on making a wiki - you'll need to make it clear the values in the PBS are not necessarily accurate.) It will apply this to all species, so any exceptions to the rules will need to be coded in that section mentioned earlier.

Option 2 - Partially Scripted​

The same code, but with an extra conditional that might yield the BaseExp value instead.
Ruby:
class Pokemon
# @return [Integer] this Pokémon's base Experience value
  def base_exp
    if species_data.base_exp == 1
      return species_data.calculated_exp
    else
      return species_data.base_exp
    end
  end
end
In this example, the game would normally check the BaseExp value in the PBS, but if that value was 1, it would use this formula to calculate exp yield instead. This can be useful if you're adding Fakemon to the canon PokéDex - you wouldn't have to worry about screwing up old values, but you could also just do BaseExp = 1 for all your Fakemon and save yourself a lot of hassle.

Option 3 - Write to the PBS​

This one's a little trickier because it involves changing the base scripts and then reverting your changes. However, I personally prefer it because the values are now written out in a document you can edit - not only can you see them for yourself (as can your players, if you leave the PBS in), but you also have more of a baseline to edit them if you want to add more exceptions. For example, if you have a Pokémon with a hindering ability like Slaking or Regigigas, you'd have a starting point for the exp yield, and could decide how much to lower it from there.

In Compiler_WritePBS, press Ctrl+H and run a search that finds base_exp and replaces it with calculated_exp, like so:
1671623083592.png

Now run your game in Debug mode and go to Debug menu->Other Options->Create PBS File(s). Create pokemon.txt and pokemon_forms.txt. The game will rewrite these files using this formula. (All other data will be kept the same)

Close out of the game, do another Ctrl+H to undo the first -
1671623258908.png

And start your game again to compile any changes.

This does have one major setback, though - it's not going to automatically update. If you add another Pokémon, you'd have to do this process all over again. (And overwrite any exceptions in the process) It's best done when all your Pokémon are implemented - and if you're already using placeholder values, you may find it easier to just take Option 2.

Related​

Credits
TechSkylander1518 for the code
Maruno, Buttjuice, and Cave of Dragonflies for sharing the formula
Author
TechSkylander1518
Views
1,481
First release
Last update
Rating
0.00 star(s) 0 ratings

More resources from TechSkylander1518

Back
Top