- Author
- Developers
Posted May 19, 2023
Adding an Ability
Next up, abilities.
Abilities, as you'd expect, are defined in PBS/abilities.txt. They're very straightforward on the PBS end of things, only requiring an ID, Internal Name, Display Name, and Description. On the other hand, the entire implementation is code based.
To fit in with Beatote's Pokedex entry of preying on Nincada, let's have its ability make its attack increase by 50% against Bug-type Pokemon.
To start, defining its ability in the PBS:
330,SCAVENGER,Scavenger,"Deal increased damage to Bug-type Pokémon."
Next, we'll give that ability to Beatote.
HiddenAbility=SCAVENGER
Now we can compile, and Beatote will now have the Scavenger ability!
Spoiler
And now, we need to implement it!
There's a lot to do here, so bear with me and try to follow along. We want to head to the file PokeBattle_Move.rb. This file is where all damage calculation takes place, and where the magic mainly happens.
You'll want to head down to around line 1448, which is after all the field effect code. You'll be looking for a line that says:
case attacker.abilitywhen PBAbilities::GUTS
In here, we'll want to add a few lines so we end up with:
case attacker.abilitywhen PBAbilities::SCAVENGERatkmult=(atkmult*1.5).round if opponent.hasType?(:BUG)when PBAbilities::GUTS
I'll explain what's going on here.
This is a method called pbCalcDamage. Inside of it, it takes three parameters in addition to an optional hitnum named parameter. While the parameters options and hitnum are inconsequential, attacker and opponent are what we really care about here. Both attacker and opponent will be PokeBattle_Battler objects, found inside PokeBattle_Battler.rb. Any method or attribute in there can be called and utilized for creating a damaging move.
The method hasType? takes a type and returns if the object has it or not.
pbCalcDamage is split into parts:
Spoiler
- Initialization, including exiting if base damage is 0, pulling base damage from PBS, etc.
- Calculate the base damage.
- Abilities, such as Sheer Force and Pixilate.
- Items, such as gems, plates, and legendary orbs (Griseous Orb, Soul Dew, etc)
- More effectsconditionally, being Charge, Helping Hand, Mud/Water Sport, Kalos Legend Abilities, Knock Off, and Lunala Z vs Minimize.
- Field effect changes.
- Calculate the attacker's attack stat comes next, being the Pokemonusingthe move.
- Determine if physical or special.
- Adjust for Unaware/Hustle/Power Spot.
- More field effects.
- Conditional attack modifier abilities (Starters, Swarm).
- Attack modifier abilities (Scavenger, Huge Power, Guts, Flash Fire, etc).
- Item modifiers, such as Light Ball, Thick Club, Choice items
- Thick Fat must be done LAST.
- Calculatethe corresponding defense stat.
- Same shtick applies here. Very repetitive.
- Calculate the effective, or actual, damage.
- Multihit moves
- Generic field boosts, such as type matching.
- Primal Abilities return 0 damage here if nullified by respective weather.
- Fieldtransformations, such as Crystal Cave > Dark Crystal Cave or Factory Field
- Sun/Rain
- Crit calculation
- Damage rolls
- STAB calculation
- Type effectiveness check
- Gem message + Burn/Water Bubble
- Effective damage mods, such as Screens, Multiscale, Friend Guard, Life Orb, Berries, etc.
- Calculate final damage using above methods.
Now your ability functions. But only for the player. The AI does not know what's actually going on with your ability, it simply sees nothing, We need to head to the file "PokeBattle_AI_2.rb".
This file is a wonder. It's incredibly complicated and I won't bore you trying to teach it. The gist is, you need to find similar functioning abilities and insert your new ability in. If you look at where we inserted Scavenger in the PokeBattle_Move.rb, we should look for spots where those abilities are and copy them, provided we ignore any field-specific effects for them. This will apply similar logic to before. I'll state which methods we'll be modifying. This part doesn'tneedto be done, but should if you plan on making the AI have a fair chance.
Certain abilities should be more weighted heavily in the first location, a method called getAbilityDisruptScore, which is the score the AI gets for whether or not it should "counter" the ability. We'll place this right near where the code for Huge Power is. The multiplier here is typically the same.
when PBAbilities::SCAVENGERabilityscore*=1.5 if opponent.hasType?(:BUG)
The next spot is where we calculate ability score for the AI to find the best switch for. It can be found by searching abilityscore in the file. It starts at around line 8035 on clean code.
Pretty much anywhere after the line case i.ability we will be adding the code:
when PBAbilities::SCAVENGERabilityscore+=30 if @opponent.hasType?(:BUG)
The amount to add here is pretty subjective. The general process is 10 for "hey this is better than no ability" or a much higher number for "hey this is a really freaking good idea do this."
However much you want to add for your own abilities is up to you.
The final spot where it's required is much further down labeled with a comment tag
############ ATTACKER ABILITY CHECKS ############
You can search for this to find it. We'll be adding this line into the code there. It can be anywhere after Technician but before Type Changing Abilities. Typically group like changes together.
#Scavengerelsif attacker.ability == PBAbilities::SCAVENGERif opponent.hasType?(:BUG)atk=(atk*1.5).roundend
Congrats! You've taken your first real step into full content mods with this! There's still awholelot going on here behind the scenes, but I'm not going to explain it solely based on the fact it would take way too long to explain everything. I've explained the important stuff, much of it has labels, and much of it is very self-explanatory thanks to our wonderful developers (humblebrag). Let's hop into the next topic.
- 3