mirror of
https://github.com/pret/pokefirered.git
synced 2026-10-01 13:29:23 -05:00
battle_util.c reordering
This commit is contained in:
@@ -7799,80 +7799,6 @@ u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc)
|
||||
return count;
|
||||
}
|
||||
|
||||
// This function is the body of "jumpifstat", but can be used dynamically in a function
|
||||
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind)
|
||||
{
|
||||
bool32 ret = FALSE;
|
||||
u8 statValue = gBattleMons[battler].statStages[statId];
|
||||
|
||||
// Because this command is used as a way of checking if a stat can be lowered/raised,
|
||||
// we need to do some modification at run-time.
|
||||
if (GetBattlerAbility(battler) == ABILITY_CONTRARY)
|
||||
{
|
||||
if (cmpKind == CMP_GREATER_THAN)
|
||||
cmpKind = CMP_LESS_THAN;
|
||||
else if (cmpKind == CMP_LESS_THAN)
|
||||
cmpKind = CMP_GREATER_THAN;
|
||||
|
||||
if (cmpTo == MIN_STAT_STAGE)
|
||||
cmpTo = MAX_STAT_STAGE;
|
||||
else if (cmpTo == MAX_STAT_STAGE)
|
||||
cmpTo = MIN_STAT_STAGE;
|
||||
}
|
||||
|
||||
switch (cmpKind)
|
||||
{
|
||||
case CMP_EQUAL:
|
||||
if (statValue == cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_NOT_EQUAL:
|
||||
if (statValue != cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_GREATER_THAN:
|
||||
if (statValue > cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_LESS_THAN:
|
||||
if (statValue < cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_COMMON_BITS:
|
||||
if (statValue & cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_NO_COMMON_BITS:
|
||||
if (!(statValue & cmpTo))
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect)
|
||||
{
|
||||
bool8 hasSereneGrace = (battlerAbility == ABILITY_SERENE_GRACE);
|
||||
bool8 hasRainbow = (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW) != 0;
|
||||
u16 secondaryEffectChance = additionalEffect->chance;
|
||||
|
||||
if (hasRainbow && hasSereneGrace && additionalEffect->moveEffect == MOVE_EFFECT_FLINCH)
|
||||
return secondaryEffectChance * 2;
|
||||
|
||||
if (hasSereneGrace)
|
||||
secondaryEffectChance *= 2;
|
||||
if (hasRainbow && additionalEffect->moveEffect != MOVE_EFFECT_SECRET_POWER)
|
||||
secondaryEffectChance *= 2;
|
||||
|
||||
return secondaryEffectChance;
|
||||
}
|
||||
|
||||
bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect)
|
||||
{
|
||||
return additionalEffect->chance == 0 || CalcSecondaryEffectChance(battler, battlerAbility, additionalEffect) >= 100;
|
||||
}
|
||||
|
||||
u32 IsAbilityOnSide(u32 battler, u32 ability)
|
||||
{
|
||||
if (IsBattlerAlive(battler) && GetBattlerAbility(battler) == ability)
|
||||
@@ -7987,29 +7913,6 @@ static bool32 TryRemoveScreens(u32 battler)
|
||||
return removed;
|
||||
}
|
||||
|
||||
// Gets move target before redirection effects etc. are applied
|
||||
// Possible return values are defined in battle.h following MOVE_TARGET_SELECTED
|
||||
u32 GetBattlerMoveTargetType(u32 battler, u32 move)
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE
|
||||
&& IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN))
|
||||
return MOVE_TARGET_BOTH;
|
||||
else
|
||||
return gMovesInfo[move].target;
|
||||
}
|
||||
|
||||
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move)
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY
|
||||
&& GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)
|
||||
&& gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK)
|
||||
return FALSE; // Pokémon affected by Heal Block cannot target allies with Pollen Puff
|
||||
if ((IsDynamaxed(battlerAtk) || gBattleStruct->dynamax.playerSelect)
|
||||
&& GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 IsMoveMakingContact(u32 move, u32 battlerAtk)
|
||||
{
|
||||
u32 atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
|
||||
@@ -8140,24 +8043,6 @@ void SetAtkCancellerForCalledMove(void)
|
||||
gBattleStruct->isAtkCancelerForCalledMove = TRUE;
|
||||
}
|
||||
|
||||
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget)
|
||||
{
|
||||
if (B_PRANKSTER_DARK_TYPES < GEN_7)
|
||||
return FALSE;
|
||||
if (!gProtectStructs[battlerPrankster].pranksterElevated)
|
||||
return FALSE;
|
||||
if (GetBattlerSide(battlerPrankster) == GetBattlerSide(battlerDef))
|
||||
return FALSE;
|
||||
if (checkTarget && (GetBattlerMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS)))
|
||||
return FALSE;
|
||||
if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK))
|
||||
return FALSE;
|
||||
if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u32 GetMoveTargetCount(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
switch (GetBattlerMoveTargetType(gBattlerAttacker, move))
|
||||
@@ -9611,16 +9496,6 @@ bool32 CanFling(u32 battler)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SetRandomMultiHitCounter()
|
||||
{
|
||||
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
|
||||
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5);
|
||||
else if (B_MULTI_HIT_CHANCE >= GEN_5)
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
|
||||
else
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.
|
||||
}
|
||||
|
||||
bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler)
|
||||
{
|
||||
if (B_BADGE_BOOST == GEN_3)
|
||||
@@ -9637,19 +9512,6 @@ bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags)
|
||||
{
|
||||
if (gBattleWeather & weatherFlags && WEATHER_HAS_EFFECT)
|
||||
{
|
||||
// given weather is active -> check if its sun, rain against utility umbrella ( since only 1 weather can be active at once)
|
||||
if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return FALSE; // utility umbrella blocks sun, rain effects
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define DAMAGE_APPLY_MODIFIER(modifier) do { \
|
||||
dmg = uq4_12_multiply_by_int_half_down(modifier, dmg); \
|
||||
} while (0)
|
||||
@@ -10274,28 +10136,6 @@ bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u8 GetBattlerGender(u32 battler)
|
||||
{
|
||||
return GetGenderFromSpeciesAndPersonality(gBattleMons[battler].species,
|
||||
gBattleMons[battler].personality);
|
||||
}
|
||||
|
||||
bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2)
|
||||
{
|
||||
u8 gender1 = GetBattlerGender(battler1);
|
||||
u8 gender2 = GetBattlerGender(battler2);
|
||||
|
||||
return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 != gender2);
|
||||
}
|
||||
|
||||
bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2)
|
||||
{
|
||||
u8 gender1 = GetBattlerGender(battler1);
|
||||
u8 gender2 = GetBattlerGender(battler2);
|
||||
|
||||
return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 == gender2);
|
||||
}
|
||||
|
||||
u32 GetBattlerHoldEffectParam(u32 battler)
|
||||
{
|
||||
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER)
|
||||
@@ -10512,106 +10352,6 @@ u32 GetBattlerAffectionHearts(u32 battler)
|
||||
return GetMonAffectionHearts(&party[gBattlerPartyIndexes[battler]]);
|
||||
}
|
||||
|
||||
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
gBattleMons[battler].level = GetMonData(mon, MON_DATA_LEVEL);
|
||||
gBattleMons[battler].hp = GetMonData(mon, MON_DATA_HP);
|
||||
gBattleMons[battler].maxHP = GetMonData(mon, MON_DATA_MAX_HP);
|
||||
gBattleMons[battler].attack = GetMonData(mon, MON_DATA_ATK);
|
||||
gBattleMons[battler].defense = GetMonData(mon, MON_DATA_DEF);
|
||||
gBattleMons[battler].speed = GetMonData(mon, MON_DATA_SPEED);
|
||||
gBattleMons[battler].spAttack = GetMonData(mon, MON_DATA_SPATK);
|
||||
gBattleMons[battler].spDefense = GetMonData(mon, MON_DATA_SPDEF);
|
||||
}
|
||||
|
||||
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
gBattleMons[battler].ability = GetMonAbility(mon);
|
||||
gBattleMons[battler].type1 = gSpeciesInfo[gBattleMons[battler].species].types[0];
|
||||
gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1];
|
||||
gBattleMons[battler].type3 = TYPE_MYSTERY;
|
||||
}
|
||||
|
||||
void RecalcBattlerStats(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
CalculateMonStats(mon);
|
||||
if (IsDynamaxed(battler) && gChosenActionByBattler[battler] != B_ACTION_SWITCH)
|
||||
ApplyDynamaxHPMultiplier(battler, mon);
|
||||
CopyMonLevelAndBaseStatsToBattleMon(battler, mon);
|
||||
CopyMonAbilityAndTypesToBattleMon(battler, mon);
|
||||
}
|
||||
|
||||
bool32 TestIfSheerForceAffected(u32 battler, u16 move)
|
||||
{
|
||||
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
|
||||
}
|
||||
|
||||
void TryRestoreHeldItems(void)
|
||||
{
|
||||
u32 i;
|
||||
u16 lostItem = ITEM_NONE;
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
if (B_RESTORE_HELD_BATTLE_ITEMS >= GEN_9 || gBattleStruct->itemLost[i].stolen)
|
||||
{
|
||||
lostItem = gBattleStruct->itemLost[i].originalItem;
|
||||
if (lostItem != ITEM_NONE && ItemId_GetPocket(lostItem) != POCKET_BERRY_POUCH)
|
||||
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &lostItem); // Restore stolen non-berry items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item)
|
||||
{
|
||||
u8 stealerSide = GetBattlerSide(battlerStealing);
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
|
||||
return FALSE;
|
||||
|
||||
// Check if the battler trying to steal should be able to
|
||||
if (stealerSide == B_SIDE_OPPONENT
|
||||
&& !(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_TRAINER_TOWER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE ? BATTLE_TYPE_TRAINER : 0)
|
||||
)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (!(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_BATTLE_TOWER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK))
|
||||
&& (gWishFutureKnock.knockedOffMons[stealerSide] & gBitTable[gBattlerPartyIndexes[battlerStealing]]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CanBattlerGetOrLoseItem(battlerItem, item) // Battler with item cannot have it stolen
|
||||
||!CanBattlerGetOrLoseItem(battlerStealing, item)) // Stealer cannot take the item
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void TrySaveExchangedItem(u32 battler, u16 stolenItem)
|
||||
{
|
||||
// Because BtlController_EmitSetMonData does SetMonData, we need to save the stolen item only if it matches the battler's original
|
||||
// So, if the player steals an item during battle and has it stolen from it, it will not end the battle with it (naturally)
|
||||
if (B_TRAINERS_KNOCK_OFF_ITEMS == FALSE)
|
||||
return;
|
||||
// If regular trainer battle and mon's original item matches what is being stolen, save it to be restored at end of battle
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
||||
&& GetBattlerSide(battler) == B_SIDE_PLAYER
|
||||
&& stolenItem == gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].originalItem)
|
||||
gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].stolen = TRUE;
|
||||
}
|
||||
|
||||
// Returns SPECIES_NONE if no form change is possible
|
||||
u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
|
||||
{
|
||||
@@ -10860,60 +10600,6 @@ bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
u16 GetUsedHeldItem(u32 battler)
|
||||
{
|
||||
return gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)];
|
||||
}
|
||||
|
||||
void RemoveConfusionStatus(u32 battler)
|
||||
{
|
||||
gBattleMons[battler].status2 &= ~STATUS2_CONFUSION;
|
||||
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
|
||||
}
|
||||
|
||||
void BufferStatChange(u32 battler, u8 statId, u8 stringId)
|
||||
{
|
||||
bool32 hasContrary = (GetBattlerAbility(battler) == ABILITY_CONTRARY);
|
||||
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
|
||||
if (stringId == STRINGID_STATFELL)
|
||||
{
|
||||
if (hasContrary)
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
|
||||
else
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
|
||||
}
|
||||
else if (stringId == STRINGID_STATROSE)
|
||||
{
|
||||
if (hasContrary)
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
|
||||
else
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
|
||||
}
|
||||
else
|
||||
{
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, stringId)
|
||||
}
|
||||
}
|
||||
|
||||
bool32 TryRoomService(u32 battler)
|
||||
{
|
||||
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN))
|
||||
{
|
||||
BufferStatChange(battler, STAT_SPEED, STRINGID_STATFELL);
|
||||
gEffectBattler = gBattleScripting.battler = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||
gBattleScripting.animArg1 = 14 + STAT_SPEED;
|
||||
gBattleScripting.animArg2 = 0;
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
u8 TryHandleSeed(u32 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute)
|
||||
{
|
||||
if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@@ -10946,25 +10632,6 @@ static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item)
|
||||
return ItemId_GetHoldEffectParam(item);
|
||||
}
|
||||
|
||||
static bool32 CanBeInfinitelyConfused(u32 battler)
|
||||
{
|
||||
if (gBattleMons[battler].ability == ABILITY_OWN_TEMPO
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 IsGen6ExpShareEnabled(void)
|
||||
{
|
||||
if (I_EXP_SHARE_FLAG <= TEMP_FLAGS_END)
|
||||
return FALSE;
|
||||
|
||||
return FlagGet(I_EXP_SHARE_FLAG);
|
||||
}
|
||||
|
||||
// Sort an array of battlers by speed
|
||||
// Useful for effects like pickpocket, eject button, red card, dancer
|
||||
void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast)
|
||||
@@ -11023,21 +10690,70 @@ bool32 CanBattlerEscape(u32 battler) // no ability check
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
|
||||
void TryRestoreHeldItems(void)
|
||||
{
|
||||
bool32 ret = TRUE;
|
||||
u32 holdEffect = GetBattlerHoldEffect(battler, TRUE);
|
||||
if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
|
||||
u32 i;
|
||||
u16 lostItem = ITEM_NONE;
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
ret = FALSE;
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
if (B_RESTORE_HELD_BATTLE_ITEMS >= GEN_9 || gBattleStruct->itemLost[i].stolen)
|
||||
{
|
||||
lostItem = gBattleStruct->itemLost[i].originalItem;
|
||||
if (lostItem != ITEM_NONE && ItemId_GetPocket(lostItem) != POCKET_BERRY_POUCH)
|
||||
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &lostItem); // Restore stolen non-berry items
|
||||
}
|
||||
}
|
||||
else if (holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
}
|
||||
|
||||
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item)
|
||||
{
|
||||
u8 stealerSide = GetBattlerSide(battlerStealing);
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
|
||||
return FALSE;
|
||||
|
||||
// Check if the battler trying to steal should be able to
|
||||
if (stealerSide == B_SIDE_OPPONENT
|
||||
&& !(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_TRAINER_TOWER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE ? BATTLE_TYPE_TRAINER : 0)
|
||||
)))
|
||||
{
|
||||
ret = FALSE;
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
return FALSE;
|
||||
}
|
||||
return ret;
|
||||
else if (!(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_BATTLE_TOWER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK))
|
||||
&& (gWishFutureKnock.knockedOffMons[stealerSide] & gBitTable[gBattlerPartyIndexes[battlerStealing]]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!CanBattlerGetOrLoseItem(battlerItem, item) // Battler with item cannot have it stolen
|
||||
||!CanBattlerGetOrLoseItem(battlerStealing, item)) // Stealer cannot take the item
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void TrySaveExchangedItem(u32 battler, u16 stolenItem)
|
||||
{
|
||||
// Because BtlController_EmitSetMonData does SetMonData, we need to save the stolen item only if it matches the battler's original
|
||||
// So, if the player steals an item during battle and has it stolen from it, it will not end the battle with it (naturally)
|
||||
if (B_TRAINERS_KNOCK_OFF_ITEMS == FALSE)
|
||||
return;
|
||||
// If regular trainer battle and mon's original item matches what is being stolen, save it to be restored at end of battle
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
||||
&& GetBattlerSide(battler) == B_SIDE_PLAYER
|
||||
&& stolenItem == gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].originalItem)
|
||||
gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].stolen = TRUE;
|
||||
}
|
||||
|
||||
bool32 DoBattlersShareType(u32 battler1, u32 battler2)
|
||||
@@ -11060,6 +10776,295 @@ bool32 DoBattlersShareType(u32 battler1, u32 battler2)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
|
||||
{
|
||||
bool32 ret = TRUE;
|
||||
u32 holdEffect = GetBattlerHoldEffect(battler, TRUE);
|
||||
if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
|
||||
{
|
||||
ret = FALSE;
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
}
|
||||
else if (holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
{
|
||||
ret = FALSE;
|
||||
RecordItemEffectBattle(battler, holdEffect);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool32 TestIfSheerForceAffected(u32 battler, u16 move)
|
||||
{
|
||||
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
|
||||
}
|
||||
|
||||
// This function is the body of "jumpifstat", but can be used dynamically in a function
|
||||
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind)
|
||||
{
|
||||
bool32 ret = FALSE;
|
||||
u8 statValue = gBattleMons[battler].statStages[statId];
|
||||
|
||||
// Because this command is used as a way of checking if a stat can be lowered/raised,
|
||||
// we need to do some modification at run-time.
|
||||
if (GetBattlerAbility(battler) == ABILITY_CONTRARY)
|
||||
{
|
||||
if (cmpKind == CMP_GREATER_THAN)
|
||||
cmpKind = CMP_LESS_THAN;
|
||||
else if (cmpKind == CMP_LESS_THAN)
|
||||
cmpKind = CMP_GREATER_THAN;
|
||||
|
||||
if (cmpTo == MIN_STAT_STAGE)
|
||||
cmpTo = MAX_STAT_STAGE;
|
||||
else if (cmpTo == MAX_STAT_STAGE)
|
||||
cmpTo = MIN_STAT_STAGE;
|
||||
}
|
||||
|
||||
switch (cmpKind)
|
||||
{
|
||||
case CMP_EQUAL:
|
||||
if (statValue == cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_NOT_EQUAL:
|
||||
if (statValue != cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_GREATER_THAN:
|
||||
if (statValue > cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_LESS_THAN:
|
||||
if (statValue < cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_COMMON_BITS:
|
||||
if (statValue & cmpTo)
|
||||
ret = TRUE;
|
||||
break;
|
||||
case CMP_NO_COMMON_BITS:
|
||||
if (!(statValue & cmpTo))
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BufferStatChange(u32 battler, u8 statId, u8 stringId)
|
||||
{
|
||||
bool32 hasContrary = (GetBattlerAbility(battler) == ABILITY_CONTRARY);
|
||||
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
|
||||
if (stringId == STRINGID_STATFELL)
|
||||
{
|
||||
if (hasContrary)
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
|
||||
else
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
|
||||
}
|
||||
else if (stringId == STRINGID_STATROSE)
|
||||
{
|
||||
if (hasContrary)
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
|
||||
else
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
|
||||
}
|
||||
else
|
||||
{
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, stringId)
|
||||
}
|
||||
}
|
||||
|
||||
bool32 TryRoomService(u32 battler)
|
||||
{
|
||||
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN))
|
||||
{
|
||||
BufferStatChange(battler, STAT_SPEED, STRINGID_STATFELL);
|
||||
gEffectBattler = gBattleScripting.battler = battler;
|
||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||
gBattleScripting.animArg1 = 14 + STAT_SPEED;
|
||||
gBattleScripting.animArg2 = 0;
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget)
|
||||
{
|
||||
if (B_PRANKSTER_DARK_TYPES < GEN_7)
|
||||
return FALSE;
|
||||
if (!gProtectStructs[battlerPrankster].pranksterElevated)
|
||||
return FALSE;
|
||||
if (GetBattlerSide(battlerPrankster) == GetBattlerSide(battlerDef))
|
||||
return FALSE;
|
||||
if (checkTarget && (GetBattlerMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS)))
|
||||
return FALSE;
|
||||
if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK))
|
||||
return FALSE;
|
||||
if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u16 GetUsedHeldItem(u32 battler)
|
||||
{
|
||||
return gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)];
|
||||
}
|
||||
|
||||
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags)
|
||||
{
|
||||
if (gBattleWeather & weatherFlags && WEATHER_HAS_EFFECT)
|
||||
{
|
||||
// given weather is active -> check if its sun, rain against utility umbrella ( since only 1 weather can be active at once)
|
||||
if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return FALSE; // utility umbrella blocks sun, rain effects
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Gets move target before redirection effects etc. are applied
|
||||
// Possible return values are defined in battle.h following MOVE_TARGET_SELECTED
|
||||
u32 GetBattlerMoveTargetType(u32 battler, u32 move)
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE
|
||||
&& IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN))
|
||||
return MOVE_TARGET_BOTH;
|
||||
else
|
||||
return gMovesInfo[move].target;
|
||||
}
|
||||
|
||||
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move)
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY
|
||||
&& GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)
|
||||
&& gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK)
|
||||
return FALSE; // Pokémon affected by Heal Block cannot target allies with Pollen Puff
|
||||
if ((IsDynamaxed(battlerAtk) || gBattleStruct->dynamax.playerSelect)
|
||||
&& GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void SetRandomMultiHitCounter()
|
||||
{
|
||||
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
|
||||
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5);
|
||||
else if (B_MULTI_HIT_CHANCE >= GEN_5)
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
|
||||
else
|
||||
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.
|
||||
}
|
||||
|
||||
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
gBattleMons[battler].level = GetMonData(mon, MON_DATA_LEVEL);
|
||||
gBattleMons[battler].hp = GetMonData(mon, MON_DATA_HP);
|
||||
gBattleMons[battler].maxHP = GetMonData(mon, MON_DATA_MAX_HP);
|
||||
gBattleMons[battler].attack = GetMonData(mon, MON_DATA_ATK);
|
||||
gBattleMons[battler].defense = GetMonData(mon, MON_DATA_DEF);
|
||||
gBattleMons[battler].speed = GetMonData(mon, MON_DATA_SPEED);
|
||||
gBattleMons[battler].spAttack = GetMonData(mon, MON_DATA_SPATK);
|
||||
gBattleMons[battler].spDefense = GetMonData(mon, MON_DATA_SPDEF);
|
||||
}
|
||||
|
||||
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
gBattleMons[battler].ability = GetMonAbility(mon);
|
||||
gBattleMons[battler].type1 = gSpeciesInfo[gBattleMons[battler].species].types[0];
|
||||
gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1];
|
||||
gBattleMons[battler].type3 = TYPE_MYSTERY;
|
||||
}
|
||||
|
||||
void RecalcBattlerStats(u32 battler, struct Pokemon *mon)
|
||||
{
|
||||
CalculateMonStats(mon);
|
||||
if (IsDynamaxed(battler) && gChosenActionByBattler[battler] != B_ACTION_SWITCH)
|
||||
ApplyDynamaxHPMultiplier(battler, mon);
|
||||
CopyMonLevelAndBaseStatsToBattleMon(battler, mon);
|
||||
CopyMonAbilityAndTypesToBattleMon(battler, mon);
|
||||
}
|
||||
|
||||
void RemoveConfusionStatus(u32 battler)
|
||||
{
|
||||
gBattleMons[battler].status2 &= ~STATUS2_CONFUSION;
|
||||
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
|
||||
}
|
||||
|
||||
static bool32 CanBeInfinitelyConfused(u32 battler)
|
||||
{
|
||||
if (gBattleMons[battler].ability == ABILITY_OWN_TEMPO
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u8 GetBattlerGender(u32 battler)
|
||||
{
|
||||
return GetGenderFromSpeciesAndPersonality(gBattleMons[battler].species,
|
||||
gBattleMons[battler].personality);
|
||||
}
|
||||
|
||||
bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2)
|
||||
{
|
||||
u8 gender1 = GetBattlerGender(battler1);
|
||||
u8 gender2 = GetBattlerGender(battler2);
|
||||
|
||||
return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 != gender2);
|
||||
}
|
||||
|
||||
bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2)
|
||||
{
|
||||
u8 gender1 = GetBattlerGender(battler1);
|
||||
u8 gender2 = GetBattlerGender(battler2);
|
||||
|
||||
return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 == gender2);
|
||||
}
|
||||
|
||||
u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect)
|
||||
{
|
||||
bool8 hasSereneGrace = (battlerAbility == ABILITY_SERENE_GRACE);
|
||||
bool8 hasRainbow = (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW) != 0;
|
||||
u16 secondaryEffectChance = additionalEffect->chance;
|
||||
|
||||
if (hasRainbow && hasSereneGrace && additionalEffect->moveEffect == MOVE_EFFECT_FLINCH)
|
||||
return secondaryEffectChance * 2;
|
||||
|
||||
if (hasSereneGrace)
|
||||
secondaryEffectChance *= 2;
|
||||
if (hasRainbow && additionalEffect->moveEffect != MOVE_EFFECT_SECRET_POWER)
|
||||
secondaryEffectChance *= 2;
|
||||
|
||||
return secondaryEffectChance;
|
||||
}
|
||||
|
||||
bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect)
|
||||
{
|
||||
return additionalEffect->chance == 0 || CalcSecondaryEffectChance(battler, battlerAbility, additionalEffect) >= 100;
|
||||
}
|
||||
|
||||
bool32 IsAlly(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
return (GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef));
|
||||
}
|
||||
|
||||
bool32 IsGen6ExpShareEnabled(void)
|
||||
{
|
||||
if (I_EXP_SHARE_FLAG <= TEMP_FLAGS_END)
|
||||
return FALSE;
|
||||
|
||||
return FlagGet(I_EXP_SHARE_FLAG);
|
||||
}
|
||||
|
||||
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
Reference in New Issue
Block a user