Buffing & Adding abilities - Pawkkie/Team-Aquas-Asset-Repo GitHub Wiki

written for expansion, version 1.8.3

Adding a new Ability (1.8.x and newer)

First things first, head over to include\contstants\abilities.h and #define our new ability. Either replace one of the unused abilities or add it to the bottom. Make sure to correct the ABILITIES_COUNT_GEN_9 if you add the ability to the bottom of this list.

image

Next, in src\data\abilities.h you need to add the ability to the Ability struct, as seen in this example below:

image

This is where all the information for your ability will go:

  • its in game name

  • its in game name if you are not using expanded ability names (only needed if your ability name is longer than 12 characters)

  • description that appears in game

  • AI rating for your ability

    • this is essentially giving a grade to the AI on how "good" an ability is to determine if it should try to use Skill Swap, Entrainment, etc. or not
  • any other applicable factors, including:

    .breakable : Mold Breaker bypasses this ability's effects

    .cantBeSwapped : Ability cannot be swapped via the move Skill Swap

    .cantBeTraced : Ability cannot be copied via the ability Trace

    .cantBeCopied : Ability cannot be copied via a move such as Entrainment or Role Play

    .cantBeOverwritten : Ability cannot be replaced with another ability via a move like Worry Seed overwritting the ability to Insomnia

    .cantBeSuppressed : Ability cannot be suppressed by another ability's effect, such as Mummy

So as an example, if I didn't want my ability to be traceable, its as easy as writing .cantBeTraced = True, inside the struct for that ability.

And then hey presto! Your ability is in the game! It doesn't do anything yet, but it exists and can be given to a pokemon.

Making your ability DO something!

The beauty of decomps is, pretty much anything you think of, can be coded in with the right know how! This post will be made with those less knowledgeable in decomps/coding/compsci, and I'll try to explain what's happening on the backend side as best I can, so that maybe you can use some of this knowledge to make your own ability changes! Without further ado, I'll share a few abilities I've worked on:

And likely more to come! Feel free to drop me a line with any ideas!

Reworked Color Change

What if Color Change activated before an incoming attack instead of after? Easy enough as long as you know where to put the code! So in order for Color Change to activate before an attack, we need to move the relevant code to something called the attackcanceler. This function is where the game handles any conditions that might result in a pokemon not being able to attack(asleep, flinched, full para, confusion self hit, etc.), thus is run before move execution.

so from src\battle_util.c, take the code inside AbilityBattleEffects for case ABILITY_COLOR_CHANGE, and delete it, as this function handles abilities activating after moves are performed, or at the end of a turn.

image

Then, this code can be added into the static void Cmd_attackcanceler(void) function. Anywhere inside the function is fine, as long as its in there! Also you can feel free to take this moment to change what parameters are required for Color Change to activate. In this example, my parameters are 1) the incoming move isn't Struggle, 2) it isn't a status move, and 3) the Color Change mon isn't already the same type as the incoming move. This is reflected in the code below:

image

And thats it! You can add/remove parameters to make it activate however you like!

Unnerve Buff

This edit asks the simple question: What if Unnerve could actually be useful outside of very niche situations? (not to mention for the player in vanilla games, this ability is nearly worthless)

Well, what if Unnerve gave contact moves an added flinch chance? What if it also stacked with moves that already have a flinch chance? What if it ALSO stacked with held items that can increase flinch chance?

Broken? Possibly. Let's do it anyway:

So this is a step above a simple copy/paste change. But easy enough in theory, as something similar to this exists in the for of Stench, which gives a 10% for any non-flinching move a chance to flinch. So we could probably borrow a little bit of code from this. Lets take a peek at it in src\battle_util.c:

image

Again, we see lined out in the code the parameters for which Stench is triggered. So lets start our improved Unnerve code with some of the basic parameters, then add some of our own.

image

Alright, so first we used gMovesInfo[gCurrentMove].makesContact == TRUE to check for a contact move. simple. Then I listed a few abilities I believe thematically should not be prone to extra flinch chances. Such abilities that suggest imposing (Intimidate & Humiliate) or resolute (Stalwart & Defiant) pokemon. (Humiliate is a SPATK version of Intimidate I added.) I suspect Shield Dust code already blocks these extra flinch chances, but it doesn't hurt to make sure the flinch chance is blocked by it. It should also be note for simplicity's sake, this is a separate case listing from the vanilla one that does not allow foes to eat berries. In much the same vein, I added in hold items that will block extra effects, as I want the Unnerve buff to interact properly with these items.

so ive defined my base flinch chance for any conatc move at 15%. tweak fchance to your liking. The for loop inside the if(MoveHasAdditionalEffects) statement (special thanks to AsparagusEduardo for this suggestion) is basically checking if a move already has a flinch chance (ex: Bite) and "cycles" thru any effects the move has until it finds the flinch chance for the move. This is relevant for moves like Fire Fang that have multiple independent possible effects. It then adds 15 to whatever this chance is. Then a simpler check for if the pokemon is holding a flinch effect item (Kings Rock/Razor Fang) and adds that 10% on top of things if applicable.

and then the meat and potatoes of the ability: if(RandomPercentage(RNG_SECONDARY_EFFECT, fchance)). What this does is determine if the move will flinch or not, based on percentage fchance. Simply put, there is fchance% the move will flinch, and a 1 - fchance% it will not.

Sinking Sands

Ok, so we've changed how an ability works, given an ability new additonal effects, now its time for a brand new made from scratch ability! Just like Mama Masuda used to make!

Jokes aside, I got this idea from a YouTube short by PokedexFillers. It works like this: you will Always move last in your priority bracket, but ALL moves do more damage based on how fast the foe is. Thematically, this makes sense since the faster you try to move in quicksand, the faster you sink.

Once we define our ability as outlined above, how do we make this happen? Well, always moving last in your priority bracket is exactly what the ability Stall does.

If we find where the code handles Stall, which is found in battle_main.c, we can go in there and similarly add Sinking Sands:

image

Alright, so there's a lot happening here, but really it's not so complex. Just a list if if/else statements where the game handles battle order, usually based on item or ability. Here is where we can see the Stall interaction being handled.

image

In simple English: If you have Stall and the foe doesn't, it sets your strikesFirst to -1, and 1 if the Foe has Stall and we do not, which is what ensures Stall will go last in its priority bracket. So to apply this to Sinking Sands, its as simple as copying these two lines exactly, and just swap in Sinking Sands in the place of Stall.

Now, to apply our damage boost based on speed. Head on over to src\battle_util,c and lets go inside the function CalcMoveBasePowerAfterModifiers. Here we can find all manner of abilities that affect base power of moves. How we configure our ability is pretty straightforward. I realized that this ability and Gyro Ball work in a similar fashion. I took a peek at EFFECT_GYRO_BALL just a bit further up in the code, and found how the game checks the speed of battlers on the field: GetBattlerTotalSpeedStat(battlerDef) and GetBattlerTotalSpeedStat(battlerAtk). And with that, we are ready to write our code!

image

First, what the heck is uq4_12_t?! Well according to the Wise Party Marsupial® RavePossum, "It's a fixed point number with 4 bits for the integer portion and 12 bits for the fractional portion. Types with _t appended to the end usually signify a typedef that's used for clarity - in this case it's a u32 under the hood, but in practice it's not treated like a normal u32. So the typedef signals more clearly how to use and interpret the variable." Or as Pawkkie eloquently stated, "the very simplified version is it lets you use fractions on what is otherwise integer hardware."

Moving right along, the ratio of speeds between the two pokemon is calculated, and based on the value of this ratio, assigns a specific modifier to the base damage of a move. The ones seen here are simply placeholders and are not final, and have not yet been fully playtested. If adding this, I'd encourage you to fiddle around with it to meet your needs.