diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index f288cfeaf..b7a60dbbb 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1838,6 +1838,10 @@ .macro trytoclearprimalweather various BS_ATTACKER, VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER .endm + + .macro setattackertostickywebuser + various BS_TARGET, VARIOUS_SET_ATTACKER_STICKY_WEB_USER + .endm .macro getrototillertargets ptr:req various BS_ATTACKER, VARIOUS_GET_ROTOTILLER_TARGETS diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index aa6c10bcb..ac2d9a1a6 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2906,6 +2906,34 @@ BattleScript_StatDownPrintString:: BattleScript_StatDownEnd:: goto BattleScript_MoveEnd +BattleScript_MirrorArmorReflect:: + pause B_WAIT_TIME_SHORT + call BattleScript_AbilityPopUp + jumpifsubstituteblocks BattleScript_AbilityNoSpecificStatLoss +BattleScript_MirrorArmorReflectStatLoss: + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_NOT_PROTECT_AFFECTED | STAT_BUFF_ALLOW_PTR, BattleScript_MirrorArmorReflectEnd + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_MirrorArmorReflectAnim + goto BattleScript_MirrorArmorReflectWontFall +BattleScript_MirrorArmorReflectAnim: + setgraphicalstatchangevalues + playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 +BattleScript_MirrorArmorReflectPrintString: + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_MirrorArmorReflectEnd: + return + +BattleScript_MirrorArmorReflectWontFall: + copybyte gBattlerTarget, gBattlerAttacker @ STRINGID_STATSWONTDECREASE uses target + goto BattleScript_MirrorArmorReflectPrintString + +@ gBattlerTarget is battler with Mirror Armor +BattleScript_MirrorArmorReflectStickyWeb: + call BattleScript_AbilityPopUp + setattackertostickywebuser + jumpifbyteequal gBattlerAttacker, gBattlerTarget, BattleScript_StickyWebOnSwitchInEnd @ Sticky web user not on field -> no stat loss + goto BattleScript_MirrorArmorReflectStatLoss + BattleScript_StatDown:: playanimation BS_EFFECT_BATTLER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printfromtable gStatDownStringIds @@ -6381,6 +6409,7 @@ BattleScript_StickyWebOnSwitchIn:: copybyte gBattlerTarget, sBATTLER printstring STRINGID_STICKYWEBSWITCHIN waitmessage B_WAIT_TIME_LONG + jumpifability BS_TARGET, ABILITY_MIRROR_ARMOR, BattleScript_MirrorArmorReflectStickyWeb statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_StickyWebOnSwitchInEnd jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_StickyWebOnSwitchInStatAnim jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StickyWebOnSwitchInEnd @@ -7955,6 +7984,7 @@ BattleScript_GrassyTerrainHealEnd: BattleScript_AbilityNoSpecificStatLoss:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp +BattleScript_AbilityNoSpecificStatLossPrint: printstring STRINGID_PKMNSXPREVENTSYLOSS waitmessage B_WAIT_TIME_LONG setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY @@ -8235,6 +8265,13 @@ BattleScript_CuteCharmActivates:: call BattleScript_TryDestinyKnotTarget return +BattleScript_GooeyActivates:: + waitstate + call BattleScript_AbilityPopUp + swapattackerwithtarget @ for defiant, mirror armor + seteffectsecondary + return + BattleScript_AbilityStatusEffect:: waitstate call BattleScript_AbilityPopUp diff --git a/include/battle.h b/include/battle.h index 5e5aa2479..770d826a5 100644 --- a/include/battle.h +++ b/include/battle.h @@ -612,6 +612,7 @@ struct BattleStruct struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member) u8 blunderPolicy:1; // should blunder policy activate u8 ballSpriteIds[2]; // item gfx, window gfx + u8 stickyWebUser; }; #define GET_MOVE_TYPE(move, typeArg) \ diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 537d9cb81..52c3c5890 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -404,6 +404,8 @@ extern const u8 BattleScript_PrimalReversion[]; extern const u8 BattleScript_HyperspaceFuryRemoveProtect[]; extern const u8 BattleScript_SelectingNotAllowedMoveGorillaTactics[]; extern const u8 BattleScript_WanderingSpiritActivates[]; +extern const u8 BattleScript_MirrorArmorReflect[]; +extern const u8 BattleScript_GooeyActivates[]; extern const u8 BattleScript_MimicryActivatesEnd3[]; extern const u8 BattleScript_ApplyMimicry[]; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index ee6cd4c7f..50db28028 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -197,7 +197,8 @@ #define VARIOUS_UPDATE_ABILITY_POPUP 124 #define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125 #define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126 -#define VARIOUS_TRY_TO_APPLY_MIMICRY 127 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127 +#define VARIOUS_TRY_TO_APPLY_MIMICRY 128 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_debug.c b/src/battle_debug.c index b34afe484..c967cfe00 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -559,7 +559,7 @@ static const struct BgTemplate sBgTemplates[] = }, { .bg = 1, - .charBaseIndex = 10, + .charBaseIndex = 2, .mapBaseIndex = 20, .screenSize = 0, .paletteMode = 0, diff --git a/src/battle_main.c b/src/battle_main.c index ad02854bd..f1adb1bfb 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -2933,6 +2933,8 @@ static void BattleStartClearSetData(void) gBattleStruct->mega.triggerSpriteId = 0xFF; + gBattleStruct->stickyWebUser = 0xFF; + for (i = 0; i < PARTY_SIZE; i++) { gBattleStruct->usedHeldItems[i][0] = 0; @@ -3030,6 +3032,9 @@ void SwitchInClearSetData(void) gBattleStruct->lastTakenMoveFrom[gActiveBattler][3] = 0; gBattleStruct->lastMoveFailed &= ~(gBitTable[gActiveBattler]); gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]); + + if (gActiveBattler == gBattleStruct->stickyWebUser) + gBattleStruct->stickyWebUser = 0xFF; // Switched into sticky web user slot so reset it for (i = 0; i < gBattlersCount; i++) { @@ -3127,6 +3132,9 @@ void FaintClearSetData(void) gBattleStruct->lastTakenMoveFrom[gActiveBattler][3] = 0; gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]); + + if (gActiveBattler == gBattleStruct->stickyWebUser) + gBattleStruct->stickyWebUser = 0xFF; // User of sticky web fainted, so reset the stored battler ID for (i = 0; i < gBattlersCount; i++) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2f4e8c46b..3bfa227bc 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2586,6 +2586,8 @@ void SetMoveEffect(bool32 primary, u32 certain) { s32 i, byTwo, affectsUser = 0; bool32 statusChanged = FALSE; + bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); + u32 flags = 0; switch (gBattleScripting.moveEffect) // Set move effects which happen later on { @@ -3016,11 +3018,16 @@ void SetMoveEffect(bool32 primary, u32 certain) case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1: + flags = affectsUser; + if (mirrorArmorReflected && !affectsUser) + flags |= STAT_BUFF_ALLOW_PTR; + if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, - affectsUser, 0)) + gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, + flags, gBattlescriptCurrInstr + 1)) { - gBattlescriptCurrInstr++; + if (!mirrorArmorReflected) + gBattlescriptCurrInstr++; } else { @@ -3058,11 +3065,15 @@ void SetMoveEffect(bool32 primary, u32 certain) case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2: + flags = affectsUser; + if (mirrorArmorReflected && !affectsUser) + flags |= STAT_BUFF_ALLOW_PTR; if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, - affectsUser, 0)) + flags, gBattlescriptCurrInstr + 1)) { - gBattlescriptCurrInstr++; + if (!mirrorArmorReflected) + gBattlescriptCurrInstr++; } else { @@ -9005,6 +9016,14 @@ static void Cmd_various(void) gBattlescriptCurrInstr += 7; } return; + case VARIOUS_SET_ATTACKER_STICKY_WEB_USER: + // For Mirror Armor: "If the Pokémon with this Ability is affected by Sticky Web, the effect is reflected back to the Pokémon which set it up. + // If Pokémon which set up Sticky Web is not on the field, no Pokémon have their Speed lowered." + gBattlerAttacker = gBattlerTarget; // Initialize 'fail' condition + SET_STATCHANGER(STAT_SPEED, 1, TRUE); + if (gBattleStruct->stickyWebUser != 0xFF) + gBattlerAttacker = gBattleStruct->stickyWebUser; + break; case VARIOUS_TRY_TO_APPLY_MIMICRY: { bool8 isMimicryDone = FALSE; @@ -9553,8 +9572,9 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr bool32 certain = FALSE; bool32 notProtectAffected = FALSE; u32 index; + bool32 affectsUser = (flags & MOVE_EFFECT_AFFECTS_USER); - if (flags & MOVE_EFFECT_AFFECTS_USER) + if (affectsUser) gActiveBattler = gBattlerAttacker; else gActiveBattler = gBattlerTarget; @@ -9655,8 +9675,9 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr } return STAT_CHANGE_DIDNT_WORK; } - else if (GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE - && !certain && statId == STAT_ACC) + else if (!certain + && ((GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && statId == STAT_ACC) + || (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && statId == STAT_ATK))) { if (flags == STAT_BUFF_ALLOW_PTR) { @@ -9669,17 +9690,16 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr } return STAT_CHANGE_DIDNT_WORK; } - else if (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER - && !certain && statId == STAT_ATK) + else if (GetBattlerAbility(gActiveBattler) == ABILITY_MIRROR_ARMOR && !affectsUser && gBattlerAttacker != gBattlerTarget && gActiveBattler == gBattlerTarget) { if (flags == STAT_BUFF_ALLOW_PTR) { + SET_STATCHANGER(statId, GET_STAT_BUFF_VALUE(statValue) | STAT_BUFF_NEGATIVE, TRUE); BattleScriptPush(BS_ptr); gBattleScripting.battler = gActiveBattler; gBattlerAbility = gActiveBattler; - gBattlescriptCurrInstr = BattleScript_AbilityNoSpecificStatLoss; - gLastUsedAbility = GetBattlerAbility(gActiveBattler); - RecordAbilityBattle(gActiveBattler, gLastUsedAbility); + gBattlescriptCurrInstr = BattleScript_MirrorArmorReflect; + RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); } return STAT_CHANGE_DIDNT_WORK; } @@ -11575,6 +11595,7 @@ static void Cmd_setstickyweb(void) { gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB; gSideTimers[targetSide].stickyWebAmount = 1; + gBattleStruct->stickyWebUser = gBattlerAttacker; // For Mirror Armor gBattlescriptCurrInstr += 5; } } diff --git a/src/battle_util.c b/src/battle_util.c index 45cba507b..a924722eb 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4986,15 +4986,16 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move case ABILITY_TANGLING_HAIR: if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerAttacker].hp != 0 - && CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN) + && (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED && IsMoveMakingContact(move, gBattlerAttacker)) { - gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_SPD_MINUS_1; + SET_STATCHANGER(STAT_SPEED, 1, TRUE); + gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; + gBattlescriptCurrInstr = BattleScript_GooeyActivates; gHitMarker |= HITMARKER_IGNORE_SAFEGUARD; effect++; }