updated up to Cmd_statbuffchange

This commit is contained in:
cawtds
2024-05-02 01:50:13 +02:00
parent 59f8a9eb31
commit 31c845e887
6 changed files with 328 additions and 91 deletions

View File

@@ -759,7 +759,7 @@
.4byte \failInstr
.endm
.macro negativedamage
.macro setdrainedhp
.byte 0x88
.endm
@@ -1929,7 +1929,7 @@
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER, \stat | \stages << 4 | \down << 7
setbyte sSTATCHANGER, \stat | \stages << 3 | \down << 7
.endm
.macro setmoveeffect effect:req

View File

@@ -119,31 +119,16 @@ BattleScript_EffectPoisonHit::
goto BattleScript_EffectHit
BattleScript_EffectAbsorb::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
critcalc
damagecalc
typecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
negativedamage
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
call BattleScript_EffectHit_Ret
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock
setdrainedhp
manipulatedamage DMG_BIG_ROOT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE
jumpifability BS_TARGET, ABILITY_LIQUID_OOZE, BattleScript_AbsorbLiquidOoze
setbyte cMULTISTRING_CHOOSER, B_MSG_ABSORB
goto BattleScript_AbsorbUpdateHp
BattleScript_AbsorbLiquidOoze::
call BattleScript_AbilityPopUpTarget
manipulatedamage DMG_CHANGE_SIGN
setbyte cMULTISTRING_CHOOSER, B_MSG_ABSORB_OOZE
BattleScript_AbsorbUpdateHp::
@@ -154,6 +139,7 @@ BattleScript_AbsorbUpdateHp::
waitmessage B_WAIT_TIME_LONG
BattleScript_AbsorbTryFainting::
tryfaintmon BS_ATTACKER
BattleScript_AbsorbHealBlock::
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
@@ -222,8 +208,9 @@ BattleScript_PreserveMissedBitDoMoveAnim:
BattleScript_EffectDreamEater::
attackcanceler
jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_DreamEaterNoEffect
jumpifsubstituteblocks BattleScript_DreamEaterNoEffect
jumpifstatus BS_TARGET, STATUS1_SLEEP, BattleScript_DreamEaterWorked
jumpifability BS_TARGET, ABILITY_COMATOSE, BattleScript_DreamEaterWorked
BattleScript_DreamEaterNoEffect:
attackstring
ppreduce
@@ -235,7 +222,6 @@ BattleScript_DreamEaterWorked:
ppreduce
critcalc
damagecalc
typecalc
adjustdamage
attackanimation
waitanimation
@@ -248,7 +234,9 @@ BattleScript_DreamEaterWorked:
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
negativedamage
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_DreamEaterTryFaintEnd
setdrainedhp
manipulatedamage DMG_BIG_ROOT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
@@ -6323,3 +6311,34 @@ BattleScript_LeafGuardPreventsRest::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectHit_Ret::
attackcanceler
BattleScript_EffectHit_RetFromAccCheck::
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
BattleScript_EffectHit_RetFromCritCalc::
critcalc
damagecalc
adjustdamage
BattleScript_Hit_RetFromAtkAnimation::
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
setadditionaleffects
return
BattleScript_ItemNoStatLoss::
pause B_WAIT_TIME_SHORT
printstring STRINGID_CLEARAMULETWONTLOWERSTATS
waitmessage B_WAIT_TIME_LONG
return

View File

@@ -774,13 +774,12 @@ extern struct BattleStruct *gBattleStruct;
|| gProtectStructs[battlerId].obstructed \
|| gProtectStructs[battlerId].silkTrapped)
#define GET_STAT_BUFF_ID(n)((n & 0xF)) // first four bits 0x1, 0x2, 0x4, 0x8
#define GET_STAT_BUFF_VALUE2(n)((n & 0xF0))
#define GET_STAT_BUFF_ID(n)((n & 7)) // first three bits 0x1, 0x2, 0x4
#define GET_STAT_BUFF_VALUE_WITH_SIGN(n)((n & 0xF8))
#define GET_STAT_BUFF_VALUE(n)(((n >> 4) & 7)) // 0x10, 0x20, 0x40
#define GET_STAT_BUFF_VALUE(n)(((n >> 3) & 0xF)) // 0x8, 0x10, 0x20, 0x40
#define STAT_BUFF_NEGATIVE 0x80 // 0x80, the sign bit
#define SET_STAT_BUFF_VALUE(n)(((s8)(((s8)(n) << 4)) & 0xF0))
#define SET_STAT_BUFF_VALUE(n)((((n) << 3) & 0xF8))
#define SET_STATCHANGER(statId, stage, goesDown)(gBattleScripting.statChanger = (statId) + (stage << 4) + (goesDown << 7))
#define SET_STATCHANGER2(dst, statId, stage, goesDown)(dst = (statId) + ((stage) << 3) + (goesDown << 7))

View File

@@ -563,8 +563,11 @@
#define STRINGID_MISTYTERRAINPREVENTS 560
#define STRINGID_PSYCHICTERRAINPREVENTS 561
#define STRINGID_FLOWERVEILPROTECTED 562
#define STRINGID_DRASTICALLY 563
#define STRINGID_SEVERELY 564
#define STRINGID_CLEARAMULETWONTLOWERSTATS 565
#define BATTLESTRINGS_COUNT 563
#define BATTLESTRINGS_COUNT 566
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,

View File

@@ -692,6 +692,9 @@ static const u8 sText_ElectricTerrainPreventsSleep[] = _("{B_DEF_NAME_WITH_PREFI
static const u8 sText_MistyTerrainPreventsStatus[] = _("{B_DEF_NAME_WITH_PREFIX} surrounds itself\nwith a protective mist!");
static const u8 sText_PsychicTerrainPreventsPriority[] = _("{B_DEF_NAME_WITH_PREFIX} surrounds itself\nwith psychic terrain!");
static const u8 sText_FlowerVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} surrounded itself\nwith a veil of petals!");
static const u8 sText_drastically[] = _("drastically ");
static const u8 sText_severely[] = _("severely ");
static const u8 sText_ClearAmuletWontLowerStats[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM} prevents\nits stats from being lowered!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] = {
@@ -1246,6 +1249,9 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_ST
[STRINGID_MISTYTERRAINPREVENTS - BATTLESTRINGS_TABLE_START] = sText_MistyTerrainPreventsStatus,
[STRINGID_PSYCHICTERRAINPREVENTS - BATTLESTRINGS_TABLE_START] = sText_PsychicTerrainPreventsPriority,
[STRINGID_FLOWERVEILPROTECTED - BATTLESTRINGS_TABLE_START] = sText_FlowerVeilProtected,
[STRINGID_DRASTICALLY - BATTLESTRINGS_TABLE_START] = sText_drastically,
[STRINGID_SEVERELY - BATTLESTRINGS_TABLE_START] = sText_severely,
[STRINGID_CLEARAMULETWONTLOWERSTATS - BATTLESTRINGS_TABLE_START] = sText_ClearAmuletWontLowerStats,
};
const u16 gTrainerUsedItemStringIds[] =

View File

@@ -323,7 +323,7 @@ static bool8 IsTwoTurnsMove(u16 move);
static void TrySetDestinyBondToHappen(void);
static u8 AttacksThisTurn(u8 battlerId, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2.
static void CheckWonderGuardAndLevitate(void);
static u8 ChangeStatBuffs(s8 statValue, u32 statId, u32, const u8 *BS_ptr);
static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr);
static void InitLevelUpBanner(void);
static bool8 SlideInLevelUpBanner(void);
static bool8 SlideOutLevelUpBanner(void);
@@ -340,6 +340,7 @@ static void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 fai
static bool8 CanBurnHitThaw(u16 move);
static bool32 ChangeOrderTargetAfterAttacker(void);
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount);
static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 isIntimidate);
static void Cmd_attackcanceler(void);
static void Cmd_accuracycheck(void);
@@ -477,7 +478,7 @@ static void Cmd_jumpifuproarwakes(void);
static void Cmd_stockpile(void);
static void Cmd_stockpiletobasedamage(void);
static void Cmd_stockpiletohpheal(void);
static void Cmd_negativedamage(void);
static void Cmd_setdrainedhp(void);
static void Cmd_statbuffchange(void);
static void Cmd_normalisebuffs(void);
static void Cmd_setbide(void);
@@ -729,8 +730,8 @@ void (* const gBattleScriptingCommandsTable[])(void) =
Cmd_stockpile, //0x85 // done
Cmd_stockpiletobasedamage, //0x86 // done
Cmd_stockpiletohpheal, //0x87 // done
Cmd_negativedamage, //0x88
Cmd_statbuffchange, //0x89
Cmd_setdrainedhp, //0x88 // done
Cmd_statbuffchange, //0x89 // done
Cmd_normalisebuffs, //0x8A
Cmd_setbide, //0x8B
Cmd_confuseifrepeatingattackends, //0x8C
@@ -11689,120 +11690,264 @@ static void Cmd_stockpiletohpheal(void)
}
}
static void Cmd_negativedamage(void)
// Sign change for drained HP handled in GetDrainedBigRootHp
static void Cmd_setdrainedhp(void)
{
gBattleMoveDamage = -(gHpDealt / 2);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = -1;
CMD_ARGS();
gBattlescriptCurrInstr++;
if (gMovesInfo[gCurrentMove].argument != 0)
gBattleMoveDamage = (gHpDealt * gMovesInfo[gCurrentMove].argument / 100);
else
gBattleMoveDamage = (gHpDealt / 2);
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattlescriptCurrInstr = cmd->nextInstr;
}
static u8 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
static u16 ReverseStatChangeMoveEffect(u16 moveEffect)
{
switch (moveEffect)
{
// +1
case MOVE_EFFECT_ATK_PLUS_1:
return MOVE_EFFECT_ATK_MINUS_1;
case MOVE_EFFECT_DEF_PLUS_1:
return MOVE_EFFECT_DEF_MINUS_1;
case MOVE_EFFECT_SPD_PLUS_1:
return MOVE_EFFECT_SPD_MINUS_1;
case MOVE_EFFECT_SP_ATK_PLUS_1:
return MOVE_EFFECT_SP_ATK_MINUS_1;
case MOVE_EFFECT_SP_DEF_PLUS_1:
return MOVE_EFFECT_SP_DEF_MINUS_1;
case MOVE_EFFECT_ACC_PLUS_1:
return MOVE_EFFECT_ACC_MINUS_1;
case MOVE_EFFECT_EVS_PLUS_1:
return MOVE_EFFECT_EVS_MINUS_1;
// -1
case MOVE_EFFECT_ATK_MINUS_1:
return MOVE_EFFECT_ATK_PLUS_1;
case MOVE_EFFECT_DEF_MINUS_1:
return MOVE_EFFECT_DEF_PLUS_1;
case MOVE_EFFECT_SPD_MINUS_1:
return MOVE_EFFECT_SPD_PLUS_1;
case MOVE_EFFECT_SP_ATK_MINUS_1:
return MOVE_EFFECT_SP_ATK_PLUS_1;
case MOVE_EFFECT_SP_DEF_MINUS_1:
return MOVE_EFFECT_SP_DEF_PLUS_1;
case MOVE_EFFECT_ACC_MINUS_1:
return MOVE_EFFECT_ACC_PLUS_1;
case MOVE_EFFECT_EVS_MINUS_1:
// +2
case MOVE_EFFECT_ATK_PLUS_2:
return MOVE_EFFECT_ATK_MINUS_2;
case MOVE_EFFECT_DEF_PLUS_2:
return MOVE_EFFECT_DEF_MINUS_2;
case MOVE_EFFECT_SPD_PLUS_2:
return MOVE_EFFECT_SPD_MINUS_2;
case MOVE_EFFECT_SP_ATK_PLUS_2:
return MOVE_EFFECT_SP_ATK_MINUS_2;
case MOVE_EFFECT_SP_DEF_PLUS_2:
return MOVE_EFFECT_SP_DEF_MINUS_2;
case MOVE_EFFECT_ACC_PLUS_2:
return MOVE_EFFECT_ACC_MINUS_2;
case MOVE_EFFECT_EVS_PLUS_2:
return MOVE_EFFECT_EVS_MINUS_2;
// -2
case MOVE_EFFECT_ATK_MINUS_2:
return MOVE_EFFECT_ATK_PLUS_2;
case MOVE_EFFECT_DEF_MINUS_2:
return MOVE_EFFECT_DEF_PLUS_2;
case MOVE_EFFECT_SPD_MINUS_2:
return MOVE_EFFECT_SPD_PLUS_2;
case MOVE_EFFECT_SP_ATK_MINUS_2:
return MOVE_EFFECT_SP_ATK_PLUS_2;
case MOVE_EFFECT_SP_DEF_MINUS_2:
return MOVE_EFFECT_SP_DEF_PLUS_2;
case MOVE_EFFECT_ACC_MINUS_2:
return MOVE_EFFECT_ACC_PLUS_2;
case MOVE_EFFECT_EVS_MINUS_2:
return MOVE_EFFECT_EVS_PLUS_2;
default:
return 0;
}
}
static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
{
bool32 certain = FALSE;
bool32 notProtectAffected = FALSE;
u32 index;
u32 index, battler, battlerAbility, battlerHoldEffect;
bool32 affectsUser = (flags & MOVE_EFFECT_AFFECTS_USER);
bool32 mirrorArmored = (flags & STAT_CHANGE_MIRROR_ARMOR);
if (flags & MOVE_EFFECT_AFFECTS_USER)
gActiveBattler = gBattlerAttacker;
if (affectsUser)
battler = gBattlerAttacker;
else
gActiveBattler = gBattlerTarget;
battler = gBattlerTarget;
gActiveBattler = battler;
flags &= ~MOVE_EFFECT_AFFECTS_USER;
battlerAbility = GetBattlerAbility(battler);
battlerHoldEffect = GetBattlerHoldEffect(battler, TRUE);
gSpecialStatuses[battler].changedStatsBattlerId = gBattlerAttacker;
flags &= ~(MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_MIRROR_ARMOR);
if (flags & MOVE_EFFECT_CERTAIN)
certain++;
certain = TRUE;
flags &= ~MOVE_EFFECT_CERTAIN;
if (flags & STAT_CHANGE_NOT_PROTECT_AFFECTED)
notProtectAffected++;
flags &= ~STAT_CHANGE_NOT_PROTECT_AFFECTED;
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId)
if (battlerAbility == ABILITY_CONTRARY)
{
statValue ^= STAT_BUFF_NEGATIVE;
gBattleScripting.statChanger ^= STAT_BUFF_NEGATIVE;
RecordAbilityBattle(battler, battlerAbility);
if (flags & STAT_CHANGE_UPDATE_MOVE_EFFECT)
{
flags &= ~STAT_CHANGE_UPDATE_MOVE_EFFECT;
gBattleScripting.moveEffect = ReverseStatChangeMoveEffect(gBattleScripting.moveEffect);
}
}
else if (battlerAbility == ABILITY_SIMPLE)
{
statValue = (SET_STAT_BUFF_VALUE(GET_STAT_BUFF_VALUE(statValue) * 2)) | ((statValue <= -1) ? STAT_BUFF_NEGATIVE : 0);
}
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
if (statValue <= -1) // Stat decrease.
{
if (gSideTimers[GET_BATTLER_SIDE(gActiveBattler)].mistTimer
&& !certain && gCurrentMove != MOVE_CURSE)
if (gSideTimers[GetBattlerSide(battler)].mistTimer
&& !certain && gCurrentMove != MOVE_CURSE
&& !(battler == gBattlerTarget && GetBattlerAbility(gBattlerAttacker) == ABILITY_INFILTRATOR))
{
if (flags == STAT_CHANGE_ALLOW_PTR)
{
if (gSpecialStatuses[gActiveBattler].statLowered)
if (gSpecialStatuses[battler].statLowered)
{
gBattlescriptCurrInstr = BS_ptr;
}
else
{
BattleScriptPush(BS_ptr);
gBattleScripting.battler = gActiveBattler;
gBattleScripting.battler = battler;
gBattlescriptCurrInstr = BattleScript_MistProtected;
gSpecialStatuses[gActiveBattler].statLowered = 1;
gSpecialStatuses[battler].statLowered = TRUE;
}
}
return STAT_CHANGE_DIDNT_WORK;
}
else if (gCurrentMove != MOVE_CURSE
&& notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(0))
&& notProtectAffected != TRUE && JumpIfMoveAffectedByProtect(gCurrentMove))
{
gBattlescriptCurrInstr = BattleScript_ButItFailed;
return STAT_CHANGE_DIDNT_WORK;
}
else if ((gBattleMons[gActiveBattler].ability == ABILITY_CLEAR_BODY
|| gBattleMons[gActiveBattler].ability == ABILITY_WHITE_SMOKE)
&& !certain && gCurrentMove != MOVE_CURSE)
else if ((battlerHoldEffect == HOLD_EFFECT_CLEAR_AMULET
|| CanAbilityPreventStatLoss(battlerAbility, GetBattlerAbility(gBattlerAttacker) == ABILITY_INTIMIDATE))
&& (!affectsUser || mirrorArmored) && !certain && gCurrentMove != MOVE_CURSE)
{
if (flags == STAT_CHANGE_ALLOW_PTR)
{
if (gSpecialStatuses[gActiveBattler].statLowered)
if (gSpecialStatuses[battler].statLowered)
{
gBattlescriptCurrInstr = BS_ptr;
}
else
{
BattleScriptPush(BS_ptr);
gBattleScripting.battler = gActiveBattler;
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
gSpecialStatuses[gActiveBattler].statLowered = 1;
gBattleScripting.battler = battler;
if (battlerHoldEffect == HOLD_EFFECT_CLEAR_AMULET)
{
gLastUsedItem = gBattleMons[battler].item;
gBattlescriptCurrInstr = BattleScript_ItemNoStatLoss;
RecordItemEffectBattle(battler, HOLD_EFFECT_CLEAR_AMULET);
}
else
{
gBattlerAbility = battler;
gBattlescriptCurrInstr = BattleScript_AbilityNoStatLoss;
gLastUsedAbility = battlerAbility;
RecordAbilityBattle(battler, gLastUsedAbility);
}
gSpecialStatuses[battler].statLowered = TRUE;
}
}
return STAT_CHANGE_DIDNT_WORK;
}
else if (gBattleMons[gActiveBattler].ability == ABILITY_KEEN_EYE
&& !certain && statId == STAT_ACC)
else if ((index = IsFlowerVeilProtected(battler)) && !certain)
{
if (flags == STAT_CHANGE_ALLOW_PTR)
{
if (gSpecialStatuses[battler].statLowered)
{
gBattlescriptCurrInstr = BS_ptr;
}
else
{
BattleScriptPush(BS_ptr);
gBattleScripting.battler = battler;
gBattlerAbility = index - 1;
gBattlescriptCurrInstr = BattleScript_FlowerVeilProtectsRet;
gLastUsedAbility = ABILITY_FLOWER_VEIL;
gSpecialStatuses[battler].statLowered = TRUE;
}
}
return STAT_CHANGE_DIDNT_WORK;
}
else if (!certain
&& (((battlerAbility == ABILITY_KEEN_EYE || battlerAbility == ABILITY_MINDS_EYE) && statId == STAT_ACC)
|| (B_ILLUMINATE_EFFECT >= GEN_9 && battlerAbility == ABILITY_ILLUMINATE && statId == STAT_ACC)
|| (battlerAbility == ABILITY_HYPER_CUTTER && statId == STAT_ATK)
|| (battlerAbility == ABILITY_BIG_PECKS && statId == STAT_DEF)))
{
if (flags == STAT_CHANGE_ALLOW_PTR)
{
BattleScriptPush(BS_ptr);
gBattleScripting.battler = gActiveBattler;
gBattleScripting.battler = battler;
gBattlerAbility = battler;
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
gLastUsedAbility = battlerAbility;
RecordAbilityBattle(battler, gLastUsedAbility);
}
return STAT_CHANGE_DIDNT_WORK;
}
else if (gBattleMons[gActiveBattler].ability == ABILITY_HYPER_CUTTER
&& !certain && statId == STAT_ATK)
else if (battlerAbility == ABILITY_MIRROR_ARMOR && !affectsUser && !mirrorArmored && gBattlerAttacker != gBattlerTarget && battler == gBattlerTarget)
{
if (flags == STAT_CHANGE_ALLOW_PTR)
{
SET_STATCHANGER(statId, GET_STAT_BUFF_VALUE(statValue) | STAT_BUFF_NEGATIVE, TRUE);
BattleScriptPush(BS_ptr);
gBattleScripting.battler = gActiveBattler;
gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
RecordAbilityBattle(gActiveBattler, gLastUsedAbility);
gBattleScripting.battler = battler;
gBattlerAbility = battler;
gBattlescriptCurrInstr = BattleScript_MirrorArmorReflect;
RecordAbilityBattle(battler, gBattleMons[battler].ability);
}
return STAT_CHANGE_DIDNT_WORK;
}
else if (gBattleMons[gActiveBattler].ability == ABILITY_SHIELD_DUST && flags == 0)
else if (battlerAbility == ABILITY_SHIELD_DUST && flags == 0)
{
RecordAbilityBattle(battler, ABILITY_SHIELD_DUST);
return STAT_CHANGE_DIDNT_WORK;
}
else if (flags == 0 && battlerHoldEffect == HOLD_EFFECT_COVERT_CLOAK)
{
RecordItemEffectBattle(battler, HOLD_EFFECT_COVERT_CLOAK);
return STAT_CHANGE_DIDNT_WORK;
}
else // try to decrease
{
statValue = -GET_STAT_BUFF_VALUE(statValue);
if (gBattleMons[battler].statStages[statId] == 1)
statValue = -1;
else if (gBattleMons[battler].statStages[statId] == 2 && statValue < -2)
statValue = -2;
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
index = 1;
if (statValue == -2)
@@ -11812,20 +11957,36 @@ static u8 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
gBattleTextBuff2[3] = STRINGID_STATHARSHLY >> 8;
index = 4;
}
else if (statValue <= -3)
{
gBattleTextBuff2[1] = B_BUFF_STRING;
gBattleTextBuff2[2] = STRINGID_SEVERELY & 0xFF;
gBattleTextBuff2[3] = STRINGID_SEVERELY >> 8;
index = 4;
}
gBattleTextBuff2[index++] = B_BUFF_STRING;
gBattleTextBuff2[index++] = STRINGID_STATFELL;
gBattleTextBuff2[index++] = STRINGID_STATFELL >> 8;
gBattleTextBuff2[index] = B_BUFF_EOS;
if (gBattleMons[gActiveBattler].statStages[statId] == MIN_STAT_STAGE)
if (gBattleMons[battler].statStages[statId] == MIN_STAT_STAGE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE;
}
else
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL
{
gProtectStructs[battler].statFell = TRUE; // Eject pack, lash out
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL
}
}
}
else // stat increase
{
statValue = GET_STAT_BUFF_VALUE(statValue);
if (gBattleMons[battler].statStages[statId] == 11)
statValue = 1;
else if (gBattleMons[battler].statStages[statId] == 10 && statValue > 2)
statValue = 2;
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
index = 1;
if (statValue == 2)
@@ -11835,22 +11996,55 @@ static u8 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8;
index = 4;
}
else if (statValue >= 3)
{
gBattleTextBuff2[1] = B_BUFF_STRING;
gBattleTextBuff2[2] = STRINGID_DRASTICALLY & 0xFF;
gBattleTextBuff2[3] = STRINGID_DRASTICALLY >> 8;
index = 4;
}
gBattleTextBuff2[index++] = B_BUFF_STRING;
gBattleTextBuff2[index++] = STRINGID_STATROSE;
gBattleTextBuff2[index++] = STRINGID_STATROSE >> 8;
gBattleTextBuff2[index] = B_BUFF_EOS;
if (gBattleMons[gActiveBattler].statStages[statId] == MAX_STAT_STAGE)
if (gBattleMons[battler].statStages[statId] == MAX_STAT_STAGE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_INCREASE;
}
else
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_ROSE or B_MSG_DEFENDER_STAT_ROSE
{
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler);
gProtectStructs[battler].statRaised = TRUE;
// check mirror herb
for (index = 0; index < gBattlersCount; index++)
{
if (GetBattlerSide(index) == GetBattlerSide(battler))
continue; // Only triggers on opposing side
if (GetBattlerAbility(index) == ABILITY_OPPORTUNIST
&& gProtectStructs[battler].activateOpportunist == 0) // don't activate opportunist on other mon's opportunist raises
{
gProtectStructs[index].activateOpportunist = 2; // set stats to copy
gQueuedStatBoosts[index].stats |= (1 << (statId - 1)); // -1 to start at atk
gQueuedStatBoosts[index].statChanges[statId - 1] += statValue; // cumulative in case of multiple opponent boosts
}
else if (GetBattlerHoldEffect(index, TRUE) == HOLD_EFFECT_MIRROR_HERB
&& gBattleMons[index].statStages[statId] < MAX_STAT_STAGE)
{
gProtectStructs[index].eatMirrorHerb = 1;
gQueuedStatBoosts[index].stats |= (1 << (statId - 1)); // -1 to start at atk
gQueuedStatBoosts[index].statChanges[statId - 1] = statValue;
}
}
}
}
gBattleMons[gActiveBattler].statStages[statId] += statValue;
if (gBattleMons[gActiveBattler].statStages[statId] < MIN_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[statId] = MIN_STAT_STAGE;
if (gBattleMons[gActiveBattler].statStages[statId] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[statId] = MAX_STAT_STAGE;
gBattleMons[battler].statStages[statId] += statValue;
if (gBattleMons[battler].statStages[statId] < MIN_STAT_STAGE)
gBattleMons[battler].statStages[statId] = MIN_STAT_STAGE;
if (gBattleMons[battler].statStages[statId] > MAX_STAT_STAGE)
gBattleMons[battler].statStages[statId] = MAX_STAT_STAGE;
if (gBattleCommunication[MULTISTRING_CHOOSER] == B_MSG_STAT_WONT_INCREASE && flags & STAT_CHANGE_ALLOW_PTR)
gMoveResultFlags |= MOVE_RESULT_MISSED;
@@ -11864,18 +12058,15 @@ static u8 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
static void Cmd_statbuffchange(void)
{
CMD_ARGS(u16 flags, const u8 *failInstr);
u16 flags = cmd->flags;
const u8 *ptrBefore = gBattlescriptCurrInstr;
const u8 *failInstr = cmd->failInstr;
if (ChangeStatBuffs(gBattleScripting.statChanger & 0xF0, GET_STAT_BUFF_ID(gBattleScripting.statChanger), flags, failInstr) == STAT_CHANGE_WORKED)
{
if (ChangeStatBuffs(GET_STAT_BUFF_VALUE_WITH_SIGN(gBattleScripting.statChanger), GET_STAT_BUFF_ID(gBattleScripting.statChanger), flags, failInstr) == STAT_CHANGE_WORKED)
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
{
gBattlescriptCurrInstr = ptrBefore;
}
else if (gBattlescriptCurrInstr == ptrBefore) // Prevent infinite looping.
gBattlescriptCurrInstr = failInstr;
}
// Haze
@@ -15493,3 +15684,22 @@ void BS_CheckParentalBondCounter(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 byIntimidate)
{
switch (abilityDef)
{
case ABILITY_CLEAR_BODY:
case ABILITY_FULL_METAL_BODY:
case ABILITY_WHITE_SMOKE:
return TRUE;
case ABILITY_INNER_FOCUS:
case ABILITY_SCRAPPY:
case ABILITY_OWN_TEMPO:
case ABILITY_OBLIVIOUS:
if (byIntimidate && (B_UPDATED_INTIMIDATE >= GEN_8))
return TRUE;
break;
}
return FALSE;
}