diff --git a/include/battle.h b/include/battle.h index 7af75c00d1..b95da58aa2 100755 --- a/include/battle.h +++ b/include/battle.h @@ -171,7 +171,8 @@ struct ProtectStruct u16 helpingHand:3; u16 assuranceDoubled:1; u16 myceliumMight:1; - u16 padding:11; + u16 revengeDoubled:4; + u16 padding:7; // End of 16-bit bitfield u16 physicalDmg; u16 specialDmg; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index acb60f3c36..2b391159cd 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1026,7 +1026,7 @@ static void TryClearChargeVolatile(u32 moveType) if (moveType == TYPE_ELECTRIC && gBattleMons[gBattlerAttacker].volatiles.chargeTimer == 1) gBattleMons[gBattlerAttacker].volatiles.chargeTimer = 0; - + for (u32 battler = 0; battler < gBattlersCount; battler++) { if (gBattleMons[battler].volatiles.chargeTimer == 2) // Has been set this turn by move @@ -2332,6 +2332,8 @@ static void PassiveDataHpUpdate(u32 battler, const u8 *nextInstr) gBattleMons[battler].hp -= gBattleStruct->passiveHpUpdate[battler]; else gBattleMons[battler].hp = 0; + // Since this is reset for the next turn, it should be fine to set it here. + gProtectStructs[battler].assuranceDoubled = TRUE; } // Send updated HP @@ -2431,7 +2433,6 @@ static void MoveDamageDataHpUpdate(u32 battler, u32 scriptBattler, const u8 *nex gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; else gProtectStructs[battler].physicalBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; } else // Physical move { @@ -2441,8 +2442,10 @@ static void MoveDamageDataHpUpdate(u32 battler, u32 scriptBattler, const u8 *nex gProtectStructs[battler].specialBattlerId = gBattlerAttacker; else gProtectStructs[battler].specialBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; } + gProtectStructs[battler].assuranceDoubled = TRUE; + gProtectStructs[battler].revengeDoubled |= 1u << gBattlerAttacker; + } // Send updated HP BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); diff --git a/src/battle_util.c b/src/battle_util.c index b2ea9d02a1..4a63e2b27f 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7036,10 +7036,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower = 100 * gDisableStructs[battlerAtk].stockpileCounter; break; case EFFECT_REVENGE: - if ((gProtectStructs[battlerAtk].physicalDmg - && gProtectStructs[battlerAtk].physicalBattlerId == battlerDef) - || (gProtectStructs[battlerAtk].specialDmg - && gProtectStructs[battlerAtk].specialBattlerId == battlerDef)) + if (gProtectStructs[battlerAtk].revengeDoubled & 1u << battlerDef) basePower *= 2; break; case EFFECT_WEATHER_BALL: diff --git a/test/battle/hold_effect/life_orb.c b/test/battle/hold_effect/life_orb.c index e983537b83..7d99449bcb 100644 --- a/test/battle/hold_effect/life_orb.c +++ b/test/battle/hold_effect/life_orb.c @@ -1,6 +1,11 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); +} + SINGLE_BATTLE_TEST("Life Orb activates when users attack is succesful") { GIVEN { diff --git a/test/battle/move_effect/assurance.c b/test/battle/move_effect/assurance.c index 6eccb48f3f..488740ec8f 100644 --- a/test/battle/move_effect/assurance.c +++ b/test/battle/move_effect/assurance.c @@ -1,11 +1,10 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Recoil"); -TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Life Orb"); -TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Crash"); -TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Confusion"); -TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Rocky Helmet"); +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_ASSURANCE) == EFFECT_ASSURANCE); +} DOUBLE_BATTLE_TEST("Assurance doubles in power if False Swipe connected but didn't do any damage") { @@ -33,3 +32,31 @@ DOUBLE_BATTLE_TEST("Assurance doubles in power if False Swipe connected but didn EXPECT_MUL_EQ(hits[0], Q_4_12(2.0), hits[1]); } } + +SINGLE_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Life Orb") +{ + s16 hits[2]; + + GIVEN { + ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_ASSURANCE); } + TURN { MOVE(player, MOVE_POUND); MOVE(opponent, MOVE_ASSURANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ASSURANCE, opponent); + HP_BAR(player, captureDamage: &hits[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player); + MESSAGE("Wobbuffet was hurt by the Life Orb!"); + HP_BAR(player, captureDamage: &hits[1]); + } THEN { + EXPECT_MUL_EQ(hits[0], Q_4_12(2.0), hits[1]); + } +} + +TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Recoil"); +TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Crash"); +TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Confusion"); +TO_DO_BATTLE_TEST("Assurance doubles in power if the target has been damaged in the same turn - Rocky Helmet"); + diff --git a/test/battle/move_effect/revenge.c b/test/battle/move_effect/revenge.c index 980bca9e33..1b5c79d00a 100644 --- a/test/battle/move_effect/revenge.c +++ b/test/battle/move_effect/revenge.c @@ -1,4 +1,69 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Revenge (Move Effect) test titles") +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_REVENGE) == EFFECT_REVENGE); +} + +SINGLE_BATTLE_TEST("Revenge doubles in power if False Swipe connected but didn't do any damage") +{ + s16 hits[3]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_REVENGE); } + TURN { MOVE(opponent, MOVE_FALSE_SWIPE); MOVE(player, MOVE_REVENGE); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_REVENGE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, player); + HP_BAR(opponent, captureDamage: &hits[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FALSE_SWIPE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, player); + HP_BAR(opponent, captureDamage: &hits[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, player); + HP_BAR(opponent, captureDamage: &hits[2]); + } THEN { + EXPECT_MUL_EQ(hits[0], Q_4_12(2.0), hits[1]); + EXPECT_EQ(hits[0], hits[2]); + } +} + +DOUBLE_BATTLE_TEST("Revenge doesn't double in power if user was not hit by target in doubles") +{ + s16 hits[3]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_REVENGE, target: playerRight); } + TURN { + MOVE(playerRight, MOVE_POUND, target: opponentRight); + MOVE(opponentLeft, MOVE_REVENGE, target: playerRight); + } + TURN { + MOVE(playerRight, MOVE_POUND, target: opponentLeft); + MOVE(opponentLeft, MOVE_REVENGE, target: playerRight); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, opponentLeft); + HP_BAR(playerRight, captureDamage: &hits[0]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, opponentLeft); + HP_BAR(playerRight, captureDamage: &hits[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVENGE, opponentLeft); + HP_BAR(playerRight, captureDamage: &hits[2]); + } THEN { + EXPECT_EQ(hits[0], hits[1]); + EXPECT_MUL_EQ(hits[1], Q_4_12(2.0), hits[2]); + } +}