• 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.

[Battle] Editing Anticipation to Avoid Super Effective

Torterra18

Base PP Gifter
32
Posts
313
Days
  • Ok, it isn't exactly asking for help, but more like asking for examples, but anyways, I want to make Anticipation give, like, a 30/20% accuracy nerf for moves that would hit SE (Super-Effective), I know that I'll do it in the file where the evasiveness functionality of Sand Veil/Snow Cloak is done, but, I asked a while ago how to do it, and they told me to define the SE thing, the problem is, Idk how to do it because I, stupidly, didn't ask for examples, which I can learn more easily VIA analysis of other parts of the code, so, what stuff do you recommend me to look into so I can do that task?
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • I asked a while ago how to do it, and they told me to define the SE thing
    What you were told is to declare a local variable that you were trying to use at the top of the function you were editing, before actually making use of it.
    Why? Because as you were also taught, you can't just throw in a local variable potatoes in some if statement at GetTotalAccuracy and expect the function to know what value is potatoes supposed to hold or what is it supposed to mean at all.

    Anyway, here's a diff for a copy of the latest Pokeemerald-expansion Master branch.
    Code:
    diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
    index 6f2403d4ea..231062afbc 100644
    --- a/src/battle_script_commands.c
    +++ b/src/battle_script_commands.c
    @@ -1856,6 +1856,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
         u8 defParam = GetBattlerHoldEffectParam(battlerDef);
         u8 atkAlly = BATTLE_PARTNER(battlerAtk);
         u16 atkAllyAbility = GetBattlerAbility(atkAlly);
    [color=SeaGreen]+    bool8 isHitSE = GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(2.0);[/color]
     
         gPotentialItemEffectBattler = battlerDef;
         accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
    @@ -1919,6 +1920,10 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
             if (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
                 calc = (calc * 50) / 100; // 1.5 tangled feet loss
             break;
    [color=SeaGreen]+    case ABILITY_ANTICIPATION:
    +        if (isHitSE)
    +            calc = (calc * 80) / 100; // 1.2 anticipation loss
    +        break;[/color]
         }
     
         // Attacker's ally's ability
    What this does is to boost the power of moves that would do Super Effective damage against the first type of the opponent.

    You can expand on these changes if you want to take into account secondary and tertiary types.

    Here's a freebie, you can call DebugPrintLevel inside the statement for case ANTICIPATION to verify that it's working.
    Ex:
    Code:
    diff --git a/include/config.h b/include/config.h
    index 2ad84f29cd..f55ec4f4a2 100644
    --- a/include/config.h
    +++ b/include/config.h
    @@ -6,7 +6,7 @@
     // still has them in the ROM. This is because the developers forgot
     // to define NDEBUG before release, however this has been changed as
     // Ruby's actual debug build does not use the AGBPrint features.
    [color=Red]-#define NDEBUG[/color]
    [color=SeaGreen]+//#define NDEBUG[/color]
     
     // To enable printf debugging, comment out "#define NDEBUG". This allows
     // the various AGBPrint functions to be used. (See include/gba/isagbprint.h).
    diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
    index 6f2403d4ea..9cae76a9af 100644
    --- a/src/battle_script_commands.c
    +++ b/src/battle_script_commands.c
    @@ -1856,6 +1856,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
         u8 defParam = GetBattlerHoldEffectParam(battlerDef);
         u8 atkAlly = BATTLE_PARTNER(battlerAtk);
         u16 atkAllyAbility = GetBattlerAbility(atkAlly);
    [color=SeaGreen]+    bool8 isHitSE = GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(2.0);[/color]
     
         gPotentialItemEffectBattler = battlerDef;
         accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
    @@ -1919,6 +1920,14 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
             if (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
                 calc = (calc * 50) / 100; // 1.5 tangled feet loss
             break;
    [color=SeaGreen]+    case ABILITY_ANTICIPATION:
    +        if (isHitSE)
    +        {
    +            DebugPrintfLevel(MGBA_LOG_DEBUG, "This is being reached! Calc is %d: ", calc);
    +            calc = (calc * 80) / 100; // 1.2 anticipation loss
    +            DebugPrintfLevel(MGBA_LOG_DEBUG, "And now it's %d:", calc);
    +        }
    +        break;[/color]
         }
     
         // Attacker's ally's ability
    Editing Anticipation to Avoid Super Effective
     
    Last edited:

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Thanks for the help Lunos, but, do you rememember that I was working in an older version?, well I had to improvise a bit, but, can I use a code similar to that one if I want to implement AI compatibility?

    PS: I've figured out how to make explosion change type, because, while surfing thru the code to figure out how dynamictype works, I've found the code for Revelation Dance, which I completely forgot it existed, and then copypasted it :)
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • Thanks for the help Lunos, but, do you rememember that I was working in an older version?
    Yes, and the code is mostly the same.
    You don't have switch statements, but you can check the ability of the attacker with defAbility just fine.

    Ex:
    Code:
        else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
            calc = (calc * 50) / 100; // 1.5 tangled feet loss
    [color=SeaGreen]+   else if (defAbility == ABILITY_ANTICIPATION && isHitSE)
    +       calc = (calc * 50) / 100; // 1.5 anticipation loss[/color]
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Ex:
    Code:
        else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
            calc = (calc * 50) / 100; // 1.5 tangled feet loss
    [color=SeaGreen]+   else if (defAbility == ABILITY_ANTICIPATION && isHitSE)
    +       calc = (calc * 50) / 100; // 1.5 anticipation loss[/color]

    I did just that Lunos
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Btw, I tried adding multiple types compatibility, I did it like this
    Code:
    bool8 isHitSE = (GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(2.0)
                    && GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type2) >= UQ_4_12(1.0))
                    || (GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(1.0)
                    && GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type2) >= UQ_4_12(2.0));
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • Btw, I tried adding multiple types compatibility, I did it like this
    Code:
    bool8 isHitSE = (GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(2.0)
                    && GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type2) >= UQ_4_12(1.0))
                    || (GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(1.0)
                    && GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type2) >= UQ_4_12(2.0));
    There's no need to do it so convolutedly when you can just do:
    Code:
    bool8 isHitSE = (GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type1) >= UQ_4_12(2.0)
                  || GetTypeModifier(gBattleMoves[move].type, gBattleMons[battlerDef].type2) >= UQ_4_12(2.0));
    Explanation: If the type of the move stored in the variable move is super effective against the defender's 1st type or 2nd type, isHitSE will return TRUE.
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • I did it like that because the pokemon I was testing with avoided a move it's first type was weak to, but it's second type resisted, resulting in a neutral move, but it avoided it anyway
     
    1,591
    Posts
    10
    Years
    • Seen Mar 20, 2024
    I think it would be better to call GET_MOVE_TYPE(), then calculate the effectiveness using CalcTypeEffectivenessMultiplier() and checking to see if the result is greater than or equal to UQ_4_12(2.0). That way you'll account for edge cases like Freeze-Dry and third types, and your code will keep working if CalcTypeEffectivenessMultiplier()gets updated at some point.
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Ok thx, unfortunately, I don't really understand it and I may leave it like that, however, once I publish it, I may release the source code, and try to learn about C for a next, more ambitious hack
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • I think it would be better to call GET_MOVE_TYPE(), then calculate the effectiveness using CalcTypeEffectivenessMultiplier() and checking to see if the result is greater than or equal to UQ_4_12(2.0). That way you'll account for edge cases like Freeze-Dry and third types, and your code will keep working if CalcTypeEffectivenessMultiplier()gets updated at some point.

    However, what if I just, y'know, use code snippets to better understand how it works in VSCode?
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • Ok thx, unfortunately, I don't really understand it and I may leave it like that
    Code:
    diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
    index 83ac411a1c..eacfc5c9d9 100644
    --- a/src/battle_script_commands.c
    +++ b/src/battle_script_commands.c
    @@ -1861,6 +1861,11 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
         u8 defParam = GetBattlerHoldEffectParam(battlerDef);
         u8 atkAlly = BATTLE_PARTNER(battlerAtk);
         u16 atkAllyAbility = GetBattlerAbility(atkAlly);
    [color=SeaGreen]+    u8 moveType;
    +    bool8 isHitSE;
    +
    +    GET_MOVE_TYPE(move, moveType);
    +    isHitSE = (CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, TRUE) >= UQ_4_12(2.0));[/color]
    
         gPotentialItemEffectBattler = battlerDef;
         accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Code:
    diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
    index 83ac411a1c..eacfc5c9d9 100644
    --- a/src/battle_script_commands.c
    +++ b/src/battle_script_commands.c
    @@ -1861,6 +1861,11 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
         u8 defParam = GetBattlerHoldEffectParam(battlerDef);
         u8 atkAlly = BATTLE_PARTNER(battlerAtk);
         u16 atkAllyAbility = GetBattlerAbility(atkAlly);
    [color=SeaGreen]+    u8 moveType;
    +    bool8 isHitSE;
    +
    +    GET_MOVE_TYPE(move, moveType);
    +    isHitSE = (CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, TRUE) >= UQ_4_12(2.0));[/color]
    
         gPotentialItemEffectBattler = battlerDef;
         accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];

    Ok thx, sorry for being annoying
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • So I pasted the code where it originally was and the compiler told me that isHitSuperEffective is used but not declared, changed it a bit and the same error persisted, legacy version problem I guess? sorry.
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • So I pasted the code where it originally was and the compiler told me that isHitSuperEffective is used but not declared, changed it a bit and the same error persisted, legacy version problem I guess? sorry.
    Post the function of code where you're using that variable, or else it's gonna be hard to give you any specific answer.
     

    Torterra18

    Base PP Gifter
    32
    Posts
    313
    Days
  • Code:
    u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move)
    {
        u32 calc, moveAcc, atkHoldEffect, atkParam, defHoldEffect, defParam, atkAbility, defAbility;
        s8 buff, accStage, evasionStage;
        bool8 isHitSuperEffective = (CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, TRUE) >= UQ_4_12(2.0));
     

    Lunos

    Random Uruguayan User
    3,115
    Posts
    15
    Years
  • Code:
    u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move)
    {
        u32 calc, moveAcc, atkHoldEffect, atkParam, defHoldEffect, defParam, atkAbility, defAbility;
        s8 buff, accStage, evasionStage;
        bool8 isHitSuperEffective = (CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, TRUE) >= UQ_4_12(2.0));
    It's not isHitSuperEffective that doesn't exist, it's clearly moveType.
    moveType is a variable that you have to add, that is meant to hold the type of the specified move via GET_MOVE_TYPE.
    Since you're trying to pass it as an argument for CalcTypeEffectivenessMultiplier, you have to declare it and assign it a value before you assign a value to isHitSuperEffective, which is where you're calling CalcTypeEffectivenessMultiplier. After all, and I told you this before, you can't feed the code a variable potato that is not declared anywhere and expect things to just work automagically.

    Now, the problem with that is that GET_MOVE_TYPE is a macro that directly fetches the type of a specified move and stores it in the variable that you specify as its 2nd parameter, it's not something that you can assign directly as a value for a local variable, you have to declare the variable as is, and then invoke GET_MOVE_TYPE somewhere below to store the specified move's type in it.

    That's the reason why in the example I showed to you above I declared the variables moveType and isHitSuperEffective without assigning an initial value to them, and then proceed to give them one just below their declaration.
     
    Last edited:
    Back
    Top