Skip to content

Commit

Permalink
Merge branch '_RHH/master' into _RHH/upcoming
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/battle_ai_util.c
#	src/battle_util.c
  • Loading branch information
AsparagusEduardo committed May 31, 2024
2 parents e3959a7 + 13d4d29 commit c79188e
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 77 deletions.
2 changes: 1 addition & 1 deletion data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -8315,7 +8315,7 @@ BattleScript_DazzlingProtected::
attackstring
ppreduce
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
call BattleScript_AbilityPopUpScripting
printstring STRINGID_POKEMONCANNOTUSEMOVE
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
Expand Down
1 change: 1 addition & 0 deletions include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ struct MoveInfo
u32 parentalBondBanned:1;
u32 skyBattleBanned:1;
u32 sketchBanned:1;
u32 padding:5; // end of word

u32 argument;

Expand Down
62 changes: 15 additions & 47 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,48 +975,21 @@ static u32 AI_GetEffectiveness(uq4_12_t multiplier)
*/
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered)
{
u32 fasterAI = 0, fasterPlayer = 0, i;
s8 prioAI = 0;
s8 prioBattler2 = 0;
u16 *battler2Moves = GetMovesArray(battler2);

// Check move priorities first.
prioAI = GetMovePriority(battlerAI, moveConsidered);
for (i = 0; i < MAX_MON_MOVES; i++)
{
prioBattler2 = GetMovePriority(battler2, battler2Moves[i]);
if (battler2Moves[i] == MOVE_NONE || battler2Moves[i] == MOVE_UNAVAILABLE
|| (prioBattler2 > prioAI && !CanIndexMoveFaintTarget(battler2, battlerAI, i , 2)))
continue;

if (prioAI > prioBattler2)
fasterAI++;
else if (prioBattler2 > prioAI)
fasterPlayer++;
}
if (prioAI > prioBattler2)
return AI_IS_FASTER;

if (fasterAI > fasterPlayer)
{
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
prioAI, prioBattler2) == 1)
return AI_IS_FASTER;
}
else if (fasterAI < fasterPlayer)
{
return AI_IS_SLOWER;
}
else
{
if (prioAI > prioBattler2)
return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
prioAI, prioBattler2) == 1)
return AI_IS_FASTER;
else
return AI_IS_SLOWER;
}
return AI_IS_SLOWER;
}

// Check if target has means to faint ai mon.
Expand Down Expand Up @@ -1731,19 +1704,14 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)

bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (defAbility == ABILITY_CONTRARY
|| defAbility == ABILITY_CLEAR_BODY
|| defAbility == ABILITY_FULL_METAL_BODY
|| defAbility == ABILITY_WHITE_SMOKE
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET)
return FALSE;

if (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY
&& defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_WHITE_SMOKE
&& AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET)
return TRUE;
return FALSE;
return (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered));
}

bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
Expand Down
2 changes: 1 addition & 1 deletion src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5097,7 +5097,7 @@ s8 GetMovePriority(u32 battler, u16 move)
gProtectStructs[battler].pranksterElevated = 1;
priority++;
}
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler))
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler) && !IsDynamaxed(battler) && !(gBattleStruct->dynamax.toDynamax & gBitTable[battler]))
{
priority++;
}
Expand Down
8 changes: 4 additions & 4 deletions src/battle_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static const u8 sText_CantEscape2[] = _("Can't escape!\p");
static const u8 sText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can't escape!");
static const u8 sText_HitXTimes[] = _("Hit {B_BUFF1} time(s)!");
static const u8 sText_PkmnFellAsleep[] = _("{B_EFF_NAME_WITH_PREFIX}\nfell asleep!");
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
static const u8 sText_PkmnAlreadyAsleep[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready asleep!");
static const u8 sText_PkmnAlreadyAsleep2[] = _("{B_ATK_NAME_WITH_PREFIX} is\nalready asleep!");
static const u8 sText_PkmnWasntAffected[] = _("{B_DEF_NAME_WITH_PREFIX}\nwasn't affected!");
Expand All @@ -103,12 +103,12 @@ static const u8 sText_PkmnBadlyPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX} is badly
static const u8 sText_PkmnEnergyDrained[] = _("{B_DEF_NAME_WITH_PREFIX} had its\nenergy drained!");
static const u8 sText_PkmnWasBurned[] = _("{B_EFF_NAME_WITH_PREFIX} was burned!");
static const u8 sText_PkmnGotFrostbite[] = _("{B_EFF_NAME_WITH_PREFIX} got frostbite!");
static const u8 sText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nburned {B_EFF_NAME_WITH_PREFIX}!");
static const u8 sText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nburned {B_EFF_NAME_WITH_PREFIX}!");
static const u8 sText_PkmnHurtByBurn[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its burn!");
static const u8 sText_PkmnHurtByFrostbite[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its frostbite!");
static const u8 sText_PkmnAlreadyHasBurn[] = _("{B_DEF_NAME_WITH_PREFIX} already\nhas a burn.");
static const u8 sText_PkmnWasFrozen[] = _("{B_EFF_NAME_WITH_PREFIX} was\nfrozen solid!");
static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!");
static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!");
static const u8 sText_PkmnIsFrozen[] = _("{B_ATK_NAME_WITH_PREFIX} is\nfrozen solid!");
static const u8 sText_PkmnWasDefrosted[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndefrosted!");
static const u8 sText_PkmnWasDefrosted2[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted!");
Expand All @@ -117,7 +117,7 @@ static const u8 sText_PkmnFrostbiteHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nfro
static const u8 sText_PkmnFrostbiteHealed2[] = _("{B_ATK_NAME_WITH_PREFIX}'s\nfrostbite was healed!");
static const u8 sText_PkmnFrostbiteHealedBy[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE}\nhealed its frostbite!");
static const u8 sText_PkmnWasParalyzed[] = _("{B_EFF_NAME_WITH_PREFIX} is paralyzed!\nIt may be unable to move!");
static const u8 sText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!");
static const u8 sText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!");
static const u8 sText_PkmnIsParalyzed[] = _("{B_ATK_NAME_WITH_PREFIX} is paralyzed!\nIt can't move!");
static const u8 sText_PkmnIsAlreadyParalyzed[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready paralyzed!");
static const u8 sText_PkmnHealedParalysis[] = _("{B_DEF_NAME_WITH_PREFIX} was\nhealed of paralysis!");
Expand Down
15 changes: 14 additions & 1 deletion src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -6231,8 +6231,19 @@ static void Cmd_moveend(void)
case MOVEEND_DANCER: // Special case because it's so annoying
if (gMovesInfo[gCurrentMove].danceMove)
{
u8 battler, nextDancer = 0;
u32 battler, nextDancer = 0;
bool32 turnOnHitmarker = FALSE;

for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++)
{
if (gSpecialStatuses[battler].dancerUsedMove)
{
// in case a battler fails to act on a Dancer-called move
turnOnHitmarker = TRUE;
break;
}
}

if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker]
|| (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove
&& gBattleStruct->bouncedMoveIsUsed)))
Expand All @@ -6248,6 +6259,8 @@ static void Cmd_moveend(void)
{
if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove)
{
if (turnOnHitmarker)
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed))
nextDancer = battler | 0x4;
}
Expand Down
77 changes: 55 additions & 22 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4970,10 +4970,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates);
effect++;
break;
SOLAR_POWER_HP_DROP:
case ABILITY_SOLAR_POWER:
if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
{
SOLAR_POWER_HP_DROP:
BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates);
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8;
if (gBattleMoveDamage == 0)
Expand Down Expand Up @@ -5045,47 +5045,77 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITYEFFECT_WOULD_BLOCK:
{
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
u16 battlerAbility = GetBattlerAbility(battler);
u16 targetAbility = GetBattlerAbility(gBattlerTarget);
const u8 * battleScriptBlocksMove = NULL;

if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gMovesInfo[move].ballisticMove))
switch (gLastUsedAbility)
{
case ABILITY_SOUNDPROOF:
if (gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
effect = 1;
break;
case ABILITY_BULLETPROOF:
if (gMovesInfo[move].ballisticMove)
effect = 1;
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
effect = 2;
break;
case ABILITY_GOOD_AS_GOLD:
if (IS_MOVE_STATUS(gCurrentMove)
&& !(moveTarget & MOVE_TARGET_USER)
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
effect = 3;
break;
}

if (!effect)
{
switch (GetBattlerAbility(BATTLE_PARTNER(battler)))
{
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
effect = 4;
break;
}
}

if (effect == 1)
{
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
battleScriptBlocksMove = BattleScript_SoundproofProtected;
effect = 1;
}
else if ((gLastUsedAbility == ABILITY_DAZZLING || gLastUsedAbility == ABILITY_QUEENLY_MAJESTY || gLastUsedAbility == ABILITY_ARMOR_TAIL || IsBattlerAlive(battler ^= BIT_FLANK))
&& (battlerAbility == ABILITY_DAZZLING || battlerAbility == ABILITY_QUEENLY_MAJESTY || battlerAbility == ABILITY_ARMOR_TAIL)
&& GetChosenMovePriority(gBattlerAttacker) > 0
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
else if (effect == 2 || effect == 4)
{
if (effect == 4)
gBattleScripting.battler = BATTLE_PARTNER(battler);
else
gBattleScripting.battler = battler;

if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
battleScriptBlocksMove = BattleScript_DazzlingProtected;
effect = 1;
}
else if (effect == 3)
{
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
}
else if (GetChosenMovePriority(gBattlerAttacker) > 0
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (targetAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
effect = 1;
}
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_GOOD_AS_GOLD
&& IS_MOVE_STATUS(gCurrentMove)
&& !(moveTarget & MOVE_TARGET_USER)
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
{
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
effect = 1;
}
if (caseID == ABILITYEFFECT_WOULD_BLOCK)
{
if (effect && gLastUsedAbility != 0xFFFF)
Expand Down Expand Up @@ -5562,6 +5592,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& RandomWeighted(RNG_STATIC, 2, 1))
{
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
Expand All @@ -5579,6 +5610,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& RandomWeighted(RNG_FLAME_BODY, 2, 1))
{
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
Expand Down Expand Up @@ -5851,6 +5883,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (IsBattlerAlive(battler)
&& (gMovesInfo[gCurrentMove].danceMove)
&& !gSpecialStatuses[battler].dancerUsedMove
&& (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED)
&& gBattlerAttacker != battler)
{
// Set bit and save Dancer mon's original target
Expand Down
1 change: 1 addition & 0 deletions src/data/abilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
.name = _("Disguise"),
.description = COMPOUND_STRING("Decoy protects it once."),
.aiRating = 8,
.breakable = TRUE,
.cantBeCopied = TRUE,
.cantBeSwapped = TRUE,
.cantBeTraced = TRUE,
Expand Down
4 changes: 3 additions & 1 deletion src/data/moves_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6331,6 +6331,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_DEF_UP_1 },
.magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5,
.ignoresSubstitute = TRUE,
.contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS,
.contestCategory = CONTEST_CATEGORY_TOUGH,
.contestComboStarterId = 0,
Expand Down Expand Up @@ -10411,7 +10412,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_ACC_UP_1 },
//.ignoresSubstitute = TRUE,
.ignoresSubstitute = B_UPDATED_MOVE_FLAGS == GEN_4,
.magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5,
.contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS,
.contestCategory = CONTEST_CATEGORY_BEAUTY,
Expand Down Expand Up @@ -14339,6 +14340,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.zMove = { .effect = Z_EFFECT_SPDEF_UP_2 },
.powderMove = TRUE,
.magicCoatAffected = TRUE,
.ignoresSubstitute = TRUE,
.contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE,
.contestCategory = CONTEST_CATEGORY_SMART,
.contestComboStarterId = 0,
Expand Down
4 changes: 4 additions & 0 deletions test/battle/ability/armor_tail.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "global.h"
#include "test/battle.h"

// Tests for Armor Tail are handled in test/battle/ability/dazzling.c
Loading

0 comments on commit c79188e

Please sign in to comment.